我正在用Rhino Mocks编写一些单元测试用于用C#编写的WPF应用程序,该应用程序使用Unity进行依赖注入并使用MVVM achitechture。我对Rhino Mocks的单元测试经验不足,所以我不确定最佳实践是什么。
在我要编写单元测试的视图模型中,有一个依赖注入数据访问类,我们称之为DataAccess,即来自我不喜欢的外部程序集。控制。 Unity容器中只注册了一个实例,因为DataAccess具有缓存,并且希望通过Unity容器在整个应用程序中共享该实例,以提高性能。现在我需要在单元测试中模拟DataAccess,因为我无法控制数据库中的数据。我想存根或期望Retrieve方法返回一个特定的值,但DataAccess没有实现一个接口,我需要存根的方法不是虚拟的。从我在线阅读的内容来看,Rhino Mocks无法覆盖非虚方法,唯一的另一种选择是使用您想要覆盖的方法来模拟接口。这些选项都不适用于这种情况,因为我不拥有DataAccess代码。我听说TypeMock能够覆盖非虚拟方法,但说服我的公司切换到付费模拟库可能不会发生,所以我坚持使用Rhino Mocks。那么有没有办法模拟这个类并用Rhino Mocks覆盖这个方法?
public class DataAccess //in an external assembly
{
public TEntity Retrieve(TKey key);
}
public class ViewModel //in the client project
{
[Dependency]
public DataAccess DataAccess { get; set; }
}
我提出了一个可能的解决方案,但它没有使用模拟,我想使用模拟,因为有很多地方我们都有这种情况。我的想法是为DataAccess创建一个包装类(假),它具有与DataAccess相同的方法和属性,除了所有重要的方法/属性都标记为虚拟,我将该类放在我的测试项目中。然后在单元测试初始化器中,我将注册从DataAccess到我的Unity容器中的包装类的类型映射,以便在我的单元测试中实例化的VM将获得包装类的实例。除了创建一堆包装类之外,你是否看到了朝这个方向发展的任何缺点?
public class DataAccessFake : DataAccess //in the test project
{
public new virtual TEntity Retrieve(TKey key) //hides the DataAccess Retrieve with a virtual one
{
return base.Retrieve(key);
}
}
答案 0 :(得分:0)
以下是我测试过的一些代码,表明建议的方法不起作用:
class Program
{
static void Main(string[] args)
{
ViewModel vm = new ViewModel()
{
DataAccess = new DataAccessFake()
};
string result = vm.Test("test"); //this returns "test_original"
}
}
public class ViewModel
{
public DataAccess DataAccess { get; set; }
public string Test(string key)
{
return DataAccess.Retrieve(key);
}
}
public class DataAccess
{
public string Retrieve(string key)
{
return key + "_original";
}
}
public class DataAccessFake : DataAccess
{
public new virtual string Retrieve(string key)
{
return key + "_fake";
}
}
如果运行此代码,Test方法的输出将为“test_original”,表明从未调用过DataAccessFake.Retrieve方法。您还可以在此类方法中放置断点以进行验证。
由于ViewModel依赖于DataAccess,它总是会调用DataAccess.Retrieve,这是一种与DataAccessFake.Retrieve完全不同的方法。
当然,如果DataAccessFake.Retrieve是DataAccess.Retrieve的重写方法,则行为会有很大不同。