C# Rhino Mocks-期望/存根来自外部依赖项的非虚拟方法

C# Rhino Mocks-期望/存根来自外部依赖项的非虚拟方法,c#,mvvm,dependency-injection,unity-container,rhino-mocks,C#,Mvvm,Dependency Injection,Unity Container,Rhino Mocks,我正在用Rhino Mock为一个用C#编写的WPF应用程序编写一些单元测试,该应用程序使用Unity进行依赖注入,并使用MVVM achitechture。我对Rhino Mock的单元测试不是很有经验,所以我不确定最佳实践是什么 在我将要编写单元测试的视图模型中,有一个依赖注入的数据访问类,我们称之为DataAccess,它来自我不控制的外部程序集。只有一个实例向Unity容器注册,因为DataAccess有一个缓存,为了提高性能,最好通过Unity容器在整个应用程序中共享该实例。现在我需要

我正在用Rhino Mock为一个用C#编写的WPF应用程序编写一些单元测试,该应用程序使用Unity进行依赖注入,并使用MVVM achitechture。我对Rhino Mock的单元测试不是很有经验,所以我不确定最佳实践是什么

在我将要编写单元测试的视图模型中,有一个依赖注入的数据访问类,我们称之为DataAccess,它来自我不控制的外部程序集。只有一个实例向Unity容器注册,因为DataAccess有一个缓存,为了提高性能,最好通过Unity容器在整个应用程序中共享该实例。现在我需要在单元测试中模拟数据访问,因为我无法控制数据库中的数据。我希望存根或期望Retrieve方法返回一个特定的值,但是DataAccess没有实现接口,并且存根所需的方法不是虚拟的。从我在网上读到的内容来看,Rhino Mocks不能覆盖非虚拟方法,唯一的其他选择是使用您想要覆盖的方法来模拟接口。这两个选项都不适用于这种情况,因为我没有DataAccess代码。我听说TypeMock能够覆盖非虚拟方法,但说服我的公司切换到付费的Mock库可能不会发生,所以我只能使用Rhino Mock。那么有没有办法模拟这个类并用Rhino mock重写这个方法呢

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; }
}
我提出了一个可能的解决方案,但它不使用mock,我想使用mock,因为在很多地方我们都会遇到这种情况。我的想法是为DataAccess创建一个包装类(fake),该类具有与DataAccess相同的方法和属性,但所有重要的方法/属性都标记为虚拟,我将把该类放在我的测试项目中。然后在单元测试初始值设定项中,我将在Unity容器中注册从DataAccess到包装类的类型映射,以便在单元测试中实例化的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);
    }
}

下面是我测试过的一些代码,它们表明建议的方法不起作用:

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_original”,这表明从未调用DataAccessFake.Retrieve方法。您还可以在此类方法中放置断点以进行验证

由于ViewModel依赖于DataAccess,它将始终调用DataAccess.Retrieve,这是一种与DataAccessFake.Retrieve完全不同的方法


当然,如果DataAccessFake.Retrieve是DataAccess.Retrieve的重写方法,则行为会非常不同。

这是否真的有效?依赖DataAccess的对象仍将调用DataAccess.Retrieve而不是DataAccessFake.Retrieve,这是两个完全不同的方法。
new
关键字表示该方法隐藏其继承的成员。所以是的,它应该称为假方法。是的。一个简单的测试表明这是有效的。啊,我明白了。我只测试了在声明为DataAccessFake时是否可以调用隐藏方法。如果声明为DataAccess,但设置为DataAccessFake的实例,则不会调用fake方法。所以我想我的想法行不通,为了做到这一点,我必须用DataAccessFake取代对DataAccess的依赖,这不是一个好的解决方案。谢谢你。