【发布时间】:2019-03-17 03:07:55
【问题描述】:
我有一个调用 MongoDB 集合的简单应用程序,它用它做各种事情。
我想使用 NUnit、Nsubstitute 对我的服务层进行单元测试,但我不知道如何模拟我的服务层使用的数据集合。
这是我目前的设置:
自动数据库:
public class AutoDb : IAutoDb
{
private readonly IMongoCollection<Auto> _AutosCollection;
public AutoDb(IConfiguration config)
{
var client = new MongoClient(config.GetConnectionString("DatabaseConnection"));
var database = client.GetDatabase("AutoDb");
_AutosCollection = database.GetCollection<Auto>("Autos");
var AutoKey = Builders<Auto>.IndexKeys;
var indexModel = new CreateIndexModel<Auto>(AutoKey.Ascending(x => x.Email), new CreateIndexOptions {Unique = true});
_AutosCollection.Indexes.CreateOne(indexModel);
}
public async Task<List<Auto>> GetAll()
{
return await _AutosCollection.Find(_ => true).ToListAsync();
}
public async Task<Auto> Get(Guid id)
{
return await _AutosCollection.Find<Auto>(o => o.Id == id).FirstOrDefaultAsync();
}
public async Task<Auto> Create(Auto Auto)
{
await _AutosCollection.InsertOneAsync(Auto);
return Auto;
}
public async Task Update(Guid id, Auto model)
{
await _AutosCollection.ReplaceOneAsync(o => o.Id == id, model);
}
public async Task Remove(Auto model)
{
await _AutosCollection.DeleteOneAsync(o => o.Id == model.Id);
}
public async Task Remove(Guid id)
{
await _AutosCollection.DeleteOneAsync(o => o.Id == id);
}
public IMongoQueryable<Auto> GetQueryable() => _AutosCollection.AsQueryable();
}
public interface IAutoDb
{
Task<List<Auto>> GetAll();
Task<Auto> Get(Guid id);
Task<Auto> Create(Auto Auto);
Task Update(Guid id, Auto model);
Task Remove(Auto model);
Task Remove(Guid id);
IMongoQueryable<Auto> GetQueryable();
}
我的服务层
public class AutoService : IAutoService
{
private readonly IAutoDb _AutoDb;
public AutoService(IAutoDb AutoDb)
{
_AutoDb = AutoDb;
}
public async Task<Auto> CreateProfile(AutoModel model)
{
var Auto = new Auto
{
Id = new Guid(),
Type = model.Type,
Name = model.Name,
};
try
{
await _AutoDb.Create(Auto);
}
catch (MongoWriteException mwx)
{
Debug.WriteLine(mwx.Message);
return null;
}
return Auto;
}
public async Task<Auto> GetAutoById(Guid id)
{
var retVal = await _AutoDb.Get(id);
return retVal;
}
public Task<Auto> EditAuto(AutoModel model)
{
throw new NotImplementedException();
}
}
public interface IAutoService
{
Task<Auto> CreateProfile(AutoModel model);
Task<Auto> EditAuto(AutoModel model);
Task<Auto> GetAutoById(Guid id);
}
我对服务层进行单元测试的尝试:
public class AutoServiceTests
{
private IAutoDb _AutoDb;
[SetUp]
public void Setup()
{
_AutoDb = Substitute.For<IAutoDb>();
// I don't know how to mock a dataset that contains
// three auto entities that can be used in all tests
}
[Test]
public async Task CreateAuto()
{
var service = new AutoService(_AutoDb);
var retVal = await service.CreateProfile(new AutoModel
{
Id = new Guid(),
Type = "Porsche",
Name = "911 Turbo",
});
Assert.IsTrue(retVal is Auto);
}
[Test]
public async Task Get3Autos() {
var service = new AutoService(_AutoDb);
// Stopped as I don't have data in the mock db
}
[Test]
public async Task Delete1AutoById() {
var service = new AutoService(_AutoDb);
// Stopped as I don't have data in the mock db
}
}
如何创建一个可供类中所有测试使用的 mockdb 集合?
【问题讨论】:
-
与其担心在这个阶段模拟库,不如创建一个
class TestAutoDb : IAutoDb实现,而不是让它由MongoDb 支持,而是让它使用List<Auto>,你可以控制你的测试。 (IMongoQueryable可能会给您带来问题。如果您的测试不需要它,您可以不执行,或更改为IQueryable。)我还考虑使用内存中的 MongoDb 进行测试。 -
@DavidTchepak 不确定我是否关注,你能在答案中演示吗?
-
@Aeseir 在我看来,您的
IAutoDb在暴露IMongoQueryable<Auto>时看起来像leaky abstraction。
标签: c# .net-core nunit nsubstitute