使用依赖注入我发现自己创建工厂来进行单元测试。这是正常的吗?

时间:2013-10-16 15:16:17

标签: .net unit-testing testing dependency-injection mocking

检查以下简化示例代码:

public class RequestManager
{
    public RequestManager()
    {

    }

    public void ProcessRequest(byte[] data)
    {
        IRequest request = new Request(data);
        request.Send();
    }
}

当我发现自己使用此代码进行测试时,我结束了:

public class RequestManager
{
    private IRequestFactory requestFactory;

    public RequestManager(IRequestFactory requestFactory)
    {
        this.requestFactory = requestFactory;
    }

    public void ProcessRequest(byte[] data)
    {
        IRequest request = this.requestFactory.CreateRequest(data);
        request.Send();
    }
}

CreateRequest方法只有新的Request(数据),所以我可以模拟工厂并返回一个模拟。

问题是我开始有很多工厂来完成如此简单的任务,我想知道这是否正常,或者是否有一种模式或其他方法可以帮助我解决这个问题。

有什么想法吗?提前谢谢。

2 个答案:

答案 0 :(得分:2)

这不仅是正常的,而且也是体面设计的标志。在正确应用DI的应用程序中,您不需要工厂:

  • 从依赖注入容器解析的对象
  • POCO / DTO(因为它们是简单的超值商店)
  • 在大多数情况下,.NET BCL对象(尽管可能会有所不同)

对于其他一切,工厂是一个不错的选择。为什么呢?

  • 它提供了统一的对象创建方式(这样整个团队知道当你需要IRequest实例时,你应该注入IRequestFactory
  • 它没有提出任何不必要的问题(例如“我应该在创建后设置SomeProperty吗?”“我使用哪种构造函数?。{ {1}}是微不足道和直观的 - 不需要解释任何事情,所有的决定都已经制定并嵌入工厂本身了。)
  • 它简化了单元测试,大大结合了模拟(特别是当无法轻易创建虚假数据的实际对象时)

除了单元测试之外,当您在3个月,6个月,12个月内返回代码时,前两个点会带来极大的好处 - 工厂 减轻开发人员做出决策关于东西这不应该要求首先作出任何决定。

而不是想知道使用哪个构造函数传递什么参数,你有一个非常简单的合同来回答所有可能的问题,而你作为一个开发人员,可以专注于实际问题。

答案 1 :(得分:1)

IRequest request = new Request(data);

这条线与Dependancy Injection完全相反。它是一种硬编码的依赖。此行将RequestManager类与Request的{​​{1}}实现绑定在一起。

也许试试这个:

IRequest

这样,public void ProcessRequest(IRequest request) { request.Send(); } 不必具有任何IRequest实现的知识。你可以把它变成一个模拟对象/存根,它甚至不会感觉到什么!当然,这意味着创建其RequestManager的类需要知道该依赖性。但是,嘿,你可以用类似的方式将它RequestManager交给它!

最后,所有依赖关注点都集中在一个点上。通常我们使用一些框架来为我们处理连接事务,例如基于XML文件。

依赖性的全部意义在于通过setter或构造函数参数提供所需的具体对象。依赖注入框架允许您将依赖项集中在一个位置,从中您可以轻松地将提供的具体类更改为需要它们的其他类。这样你就可以在测试中使用模拟对象进行设置 - 非常方便!

Here你可以找到一篇关于依赖性注射的精彩文章