一个月前,我读完了《单元测试的艺术》一书,今天我终于有时间开始使用 Rhino Mocks 来对一个向设备发送/接收消息(UDP)并从数据库保存/加载数据的服务进行单元测试。
当然我想隔离数据库和UDP通信。

例如,对于数据库访问,我们有一些带有静态方法的类,我们称它们为:

  • 区域ADBAccess
  • 区域BDB访问
  • 区域CDB接入

这些类具有执行数据库访问的静态方法。
为了能够存根它们,我将它们的方法公开为虚拟的。

然后我开始重构代码,以便能够替换代码上这些类的实例。
在尝试了不同的事情之后,我最终得到了一个工厂类,它似乎让事情变得如此简单。

public class ObjectFactory
{
    private static Dictionary<Type, object> Instances = new Dictionary<Type, object>();

    public static T GetInstance<T>() where T : new()
    {
        if(Instances.ContainsKey(typeof(T)))
            return (T)Instances[typeof(T)];

        return new T();
    }

    public static void SetInstance<T>(object obj)
    {
        Instances[typeof(T)] = obj;
    }
}

然后在代码上,我可以使用

private AreaADBAccess DBAccess = ObjectFactory.GetInstance<AreaADBAccess>();

在测试方法上我做了类似的事情

AreaADBAccess dbAccess = mocks.Stub<AreaADBAccess>();
using (mocks.Record())
{
...
}
ObjectFactory.SetInstance<AreaADBAccess>(dbAccess);
//Invoke the test method
...

这是第一个解决方案,我意识到可以用更好的方式来完成。
您现在可以发表评论并指出最佳实践吗?
您还能向我解释一下为什么我想要一个接口而不是将方法定义为虚拟方法吗?在两处重复方法头似乎没什么用。
谢谢!

有帮助吗?

解决方案

也许你可以使用像 Windsor、StructureMap 或 Ninject 这样的 IoC 容器,这会让你的生活变得更轻松,事实上它们也可以作为你手动创建的“工厂”,但功能更强大。

还有自动模拟容器,它会自动为您的类创建模拟依赖项,这样您就可以节省额外的代码行,并使您的测试不那么脆弱。

至于需要接口而不是类的问题,它基本上是依赖倒置原则,它指出较高级别的模块(类)不应该依赖于较低级别的模块(类),它们都应该依赖于抽象。接口就是那些抽象。我建议你看看 S.O.L.I.D 原则,这会让你的生活变得更轻松,至少他们对我来说是这样。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top