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());