2

我有以下情况:

public void DoSomething(...)
{
   ...
   ClassA obj1 = new ClassA();
   ClassB obj2 = new ClassB();
   ClassC obj3 = new ClassC();
   ...
}

我知道如果我使用依赖倒置原则,我可以模拟接口并且它会起作用。问题是这些实例仅在此方法中需要,因此在类级别创建它们没有意义。最重要的是,有些方法有 5-6 个对象声明,因此将这些作为参数传递会使参数列表膨胀。

无论如何我可以使用 Moq、NMock 等来模拟这些类(它们基于一个通用接口)?

4

2 回答 2

2

如果您只需要在方法中实例化这些类型,那么您是对的,它们不应该被注入到类中。

相反,典型的解决方案是注入一个允许您的方法解析接口的工厂。

这是通常的方法:

interface IMessageFactory
{
    IMessage CreateMessage(string text);   
}

class ConcreteMessageFactory : IMessageFactory
{
    IMessage CreateMessage(string text) { return new Message(text); }
}

class MockMessageFactory : IMessageFactory
{
    public IMessage CreateMessage(string text) { return new MockMessage(text); }
}


class MyClient
{
    private readonly IMessageFactory _msgFactory;

    public MyClient(IMessageFactory msgFactory)
    {
        _msgFactory = msgFactory;   
    }

    public void SendMessage(string text)
    {
        IMessage msg = _msgFactory.CreateMessage(text);
        msg.Send();
    }
}


//Usage:
new MyClient(new ConcreteMessageFactory());
//Mocking
new MyClient(new MockMessageFactory());

根据您使用的 DI 框架,该框架可以让您更轻松地实现这种方式。例如,Castle Windsor 允许您注入一个基于委托的工厂,而不是上面的基于接口的工厂:

class MyClient
{
    private readonly Func<string, IMessage> _msgFactory;

    public MyClient(Func<string, IMessage> msgFactory)
    {
        _msgFactory = msgFactory;   
    }

    public void SendMessage(string text)
    {
        IMessage msg = _msgFactory(text);
        msg.Send();
    }
}

//Usage:
new MyClient(() => new Message());
//Mocking
new MyClient(() => new MockMessage());
于 2014-07-23T23:07:45.633 回答
1

您可以使用 StructureMap 之类的东西为您完成工作,您的方法将变成类似的东西。

public void DoSomething(...)
{
   ...
   IClassA obj1 = ObjectFactory.GetInstance<IClassA>();
   IClassB obj2 = ObjectFactory.GetInstance<IClassB>();
   IClassC obj3 = ObjectFactory.GetInstance<IClassC>();
   ...
}

然后通常你会在 global.asax 或类似文件中像这样映射它们

        ObjectFactory.Initialize(x =>
        {
            x.ForRequestedType<IClassA>().TheDefaultIsConcreteType<ClassA>();
            ...etc
        });

但是对于您的单元测试

        ObjectFactory.Initialize(x =>
        {
            x.ForRequestedType<IClassA>().TheDefaultIsConcreteType<UnitTestClassA>();
            ...etc
        });
于 2014-07-23T23:02:35.300 回答