我有一些代码(C#.Net Core WebAPI)我希望进行单元测试,但需要一些帮助,因为依赖对我来说有点奇怪。
代码来自一些示例代码(我在网上找到),用于使用.Net Core WebAPI访问MongoDb,最初看起来还不错,直到现在......
DbContext和Repository都具有相同的依赖关系 - 而Repository只是将其传递给DbContext - 因为Repository实例化了DbContext:
public class LogItemRepository : ILogItemRepository
{
private readonly DbContext _context = null;
public LogItemRepository(IOptions<DbSettings> settings)
{
_context = new DbContext(settings);
}
...
public class DbContext
{
private readonly IMongoDatabase _database = null;
public DbContext(IOptions<DbSettings> settings)
{
var client = new MongoClient(settings.Value.ConnectionString);
if (client != null)
_database = client.GetDatabase(settings.Value.Database);
}
public IMongoCollection<LogItem> LogItemsCollection
{
get
{
return _database.GetCollection<LogItem>("LogItem");
}
}
}
}
我不熟悉Options pattern,但从快速阅读看起来很不错。但我不相信做出子依赖(选项),父对象的依赖(如上例所示)是一种好习惯。
相反,我应该创建一个接口,IDbContext,并将其用作存储库的依赖项?这就是我过去所做的 - 但不确定这是否打破了期权模式。
我怀疑这是主观的,但我想要其他一些意见。
由于 添
答案 0 :(得分:1)
虽然主要基于意见,但通常的做法是不在存储库的构造函数中实例化db上下文。这将存储库与上下文紧密联系在一起。按照您在OP中的说明注入抽象。
我可能会在这里分裂头发,但在提供的示例中仍然存在太多的紧耦合。
首先抽象上下文
public interface IDbContext {
IMongoCollection<LogItem> LogItemsCollection { get; }
}
并且IMongoDatabase
也是显式依赖
public class DbContext : IDbContext {
private readonly IMongoDatabase database = null;
public DbContext(IMongoDatabase database)
this.database = database;
}
public IMongoCollection<LogItem> LogItemsCollection {
get {
return database.GetCollection<LogItem>("LogItem");
}
}
}
使用组合根(Startup)中需要的选项来配置服务。您甚至会考虑将其封装在扩展方法中。
services.AddScoped<IMongoDatabase>(provider => {
var settings = provider.GetService<IOptions<DbSettings>>();
var client = new MongoClient(settings.Value.ConnectionString);
return client.GetDatabase(settings.Value.Database);
});
services.AddScoped<IDbContext, DbContext>();
services.AddScoped<ILogItemRepository, LogItemRepository>();
//...NOTE: Use the desired service lifetime. This is just an example
这使得存储库显然依赖于上下文抽象
public class LogItemRepository : ILogItemRepository {
private readonly IDbContext context = null;
public LogItemRepository(IDbContext context) {
this.context = context;
}
//...other code
}
现在所有图层都被解耦并明确说明它们的依赖关系,允许根据需要进行更多的隔离单元测试。