C# 单元测试时在方法内部创建的模拟对象

C# 单元测试时在方法内部创建的模拟对象,c#,unit-testing,moq,nmock,C#,Unit Testing,Moq,Nmock,我有以下一个场景: public void DoSomething(...) { ... ClassA obj1 = new ClassA(); ClassB obj2 = new ClassB(); ClassC obj3 = new ClassC(); ... } 我知道如果我使用依赖倒置原则,我可以模拟接口,它会工作。问题是这些实例只在这个方法中需要,所以在类级别创建它们是没有意义的。除此之外,有些方法有5-6个对象声明,因此将它们作为参数传递会使参数列表膨

我有以下一个场景:

public void DoSomething(...)
{
   ...
   ClassA obj1 = new ClassA();
   ClassB obj2 = new ClassB();
   ClassC obj3 = new ClassC();
   ...
}
我知道如果我使用依赖倒置原则,我可以模拟接口,它会工作。问题是这些实例只在这个方法中需要,所以在类级别创建它们是没有意义的。除此之外,有些方法有5-6个对象声明,因此将它们作为参数传递会使参数列表膨胀


我是否可以使用Moq、NMock等来模拟这些类(基于公共接口)?

您可以使用StructureMap之类的工具来完成这项工作,您的方法将类似于

public void DoSomething(...)
{
   ...
   IClassA obj1 = ObjectFactory.GetInstance<IClassA>();
   IClassB obj2 = ObjectFactory.GetInstance<IClassB>();
   IClassC obj3 = ObjectFactory.GetInstance<IClassC>();
   ...
}
public void DoSomething(…)
{
...
IClassA obj1=ObjectFactory.GetInstance();
IClassB obj2=ObjectFactory.GetInstance();
IClassC obj3=ObjectFactory.GetInstance();
...
}
然后,通常您会在global.asax或类似文件中这样映射它们

        ObjectFactory.Initialize(x =>
        {
            x.ForRequestedType<IClassA>().TheDefaultIsConcreteType<ClassA>();
            ...etc
        });
ObjectFactory.Initialize(x=>
{
x、 ForRequestedType()。默认的ConcreteType();
等
});
但是对于您的单元测试

        ObjectFactory.Initialize(x =>
        {
            x.ForRequestedType<IClassA>().TheDefaultIsConcreteType<UnitTestClassA>();
            ...etc
        });
ObjectFactory.Initialize(x=>
{
x、 ForRequestedType()。默认的ConcreteType();
等
});

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

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

以下是通常的方法:

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());
类MyClient
{
私有只读功能工厂;
公共MyClient(Func MSGFFactory)
{
_msgFactory=msgFactory;
}
公共无效发送消息(字符串文本)
{
IMessage msg=_msgFactory(文本);
msg.Send();
}
}
//用法:
新建MyClient(()=>newmessage());
//嘲弄
新建MyClient(()=>新建MockMessage());