我有很多使用WPF和MVVM的系统。为了进行单元测试,我们向视图模型注入依赖项,但是我发现当在构造函数中注入依赖类时,我们无法控制其生命周期,例如Entity Framework DbContext。
一个简单的场景如下:
public class FooVM
{
private readonly IBarService _barService;
// Set in the UI via Databinding
public string Name { get; set; }
public string OtherName { get; set; }
public FooVM(IBarService barService)
{
_barService = barService;
}
public void SaveFoo()
{
_barService.SaveFoo(Name);
}
public void SaveBar()
{
_barService.SaveBar(OtherName);
}
}
public class BarService : IBarService
{
private readonly IEntityContext _entityContext;
public BarService(IEntityContext entityContext)
{
_entityContext = entityContext;
}
public void SaveFoo(string name)
{
// some EF stuff here
_entityContext.SaveChanges();
}
public void SaveBar(string otherName)
{
// some EF stuff here
_entityContext.SaveChanges();
}
}
VM需要使用服务,因此已经将其注入,服务需要一个IEntityContext,因此也被注入了该对象。问题在于,当我们在VM中调用SaveFoo和SaveBar时,_entityContext对象在单个调用后就变得脏了。理想情况下,我们希望在每次调用后处理_entityContext对象。我发现唯一的解决方法是使用依赖注入来注入容器,然后按照以下方式调用代码:
public class FooVM
{
private readonly IInjector _injector;
// Set in the UI via Databinding
public string Name { get; set; }
public string OtherName { get; set; }
public FooVM(IInjector injector)
{
_injector = injector;
}
public void SaveFoo()
{
var barService = _injector.GetUniqueInstance<IBarService>();
barService.SaveFoo(Name);
}
public void SaveBar()
{
var barService = _injector.GetUniqueInstance<IBarService>();
barService.SaveBar(OtherName);
}
}
以这种方式,容器(
IInjector
)充当一个服务定位器的角色,这样做很好,但在单元测试中不太灵活。有更好的方法来管理这个吗?我知道这样做几乎使依赖注入的所有好处都失效了,但我找不到其他方法。编辑:进一步的例子
假设您有一个带有两个按钮的窗口。其中一个服务通过依赖注入注入到其中。您单击按钮A并加载对象,然后对其进行修改并保存,但是由于某些原因(比如DbContext中的某些验证失败),此操作失败,您会看到一条友好的消息。
现在,您单击按钮2。它加载一个不同的对象并对其进行修改并尝试保存,但由于先前单击了按钮A,而且服务是相同的服务,并且具有相同的上下文,所以此操作将因为与单击按钮A时相同的原因而失败。