首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >单元测试时在方法内部创建的模拟对象

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

Stack Overflow用户
提问于 2014-07-24 06:55:53
回答 2查看 2.3K关注 0票数 2

我有一个场景:

代码语言:javascript
复制
public void DoSomething(...)
{
   ...
   ClassA obj1 = new ClassA();
   ClassB obj2 = new ClassB();
   ClassC obj3 = new ClassC();
   ...
}

我知道,如果我使用依赖反转原则,我可以模拟接口,它将工作。问题是这些实例只在这个方法中需要,所以在类级别创建它们没有意义。最重要的是,一些方法有5-6个对象声明,因此将这些作为参数传递会使参数列表变得臃肿。

有没有什么办法我可以使用Moq,NMock等来模拟这些类(它们基于一个公共接口)?

EN

回答 2

Stack Overflow用户

发布于 2014-07-24 07:07:46

如果只需要在该方法中实例化这些类型,那么就不应该将它们注入到类中,这一点是正确的。

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

下面是常用的方法:

代码语言:javascript
复制
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允许您注入delegate-based factory,而不是上面基于接口的工厂:

代码语言:javascript
复制
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());
票数 2
EN

Stack Overflow用户

发布于 2014-07-24 07:02:35

你可以使用像StructureMap这样的东西来为你做这项工作,你的方法就会变成这样。

代码语言:javascript
复制
public void DoSomething(...)
{
   ...
   IClassA obj1 = ObjectFactory.GetInstance<IClassA>();
   IClassB obj2 = ObjectFactory.GetInstance<IClassB>();
   IClassC obj3 = ObjectFactory.GetInstance<IClassC>();
   ...
}

然后通常你会像这样在global.asax或类似的地方映射它们

代码语言:javascript
复制
        ObjectFactory.Initialize(x =>
        {
            x.ForRequestedType<IClassA>().TheDefaultIsConcreteType<ClassA>();
            ...etc
        });

但是对于你的单元测试

代码语言:javascript
复制
        ObjectFactory.Initialize(x =>
        {
            x.ForRequestedType<IClassA>().TheDefaultIsConcreteType<UnitTestClassA>();
            ...etc
        });
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/24922416

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档