0

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

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

  • 区域ADBAccess
  • 区域BDBAccess
  • 区域CDBAccess

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

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

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
...

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

4

1 回答 1

4

可能您可以使用 Windsor、StructureMap 或 Ninject 等 IoC 容器,这将使您的生活更轻松,事实上它们也可以作为您手动创建的“工厂”工作,但功能更强大。

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

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

于 2010-02-24T18:53:44.230 回答