如何强制方法使用模拟?

时间:2014-12-16 19:13:57

标签: c# unit-testing mocking moq

我的应用程序由各种具体的Job类组成(所有类都继承自抽象的Job类)。在他们的Run()方法中,他们通常调用外部服务。 我想测试我的工作类并模拟服务结果。

以下是典型的具体Run()方法:

    InstallWpJobResult result = new InstallWpJobResult();
    WpManager wpManager = new WpManager();
    if (!WpManager.InstallWp(Domain, SiteTitle, WpUsername, WpPassword, WpEmail))
        result.Error = "Error installing WordPress";
    return result;

我希望WpManager.InstallWp返回true(在模拟版本中)。 我知道如何模拟对象和方法但是如何让我的工作使用模拟版本? (现在它在方法本身中创建了一个实例)。

顺便说一下,我使用Moq框架进行模拟。

2 个答案:

答案 0 :(得分:3)

一些选择:

  1. 使用构建模拟WpManager的方法定义注入到作业类中的工厂服务IWpManagerFactory。
  2. 在作业中定义一个虚拟方法BuildWpManager,并覆盖测试中的方法以注入模拟。

  3. 工厂服务方法的快速示例:

    public interface IWpManagerFactory
    {
        WpManager BuildWpManager();
    }
    
    public sealed class Tests
    {
        public void Test()
        {
            var manager = new Mock<WpManager>();
            //Set up mock manager here...
    
            var factory = new Mock<IWpManagerFactory>();
            factory.Setup(f => f.BuildWpManager()).Returns(manager.Object);
    
            //Inject factory to class under test and execute the method under test...
        }
    }
    

    这当然假设您的WpManager具有可以模拟的虚拟方法。如果没有,你也需要提取一个IWpManager接口,然后再模拟它。

答案 1 :(得分:0)

在消费者类中实例化具体类违反了SOLID原则之一(“D”或“依赖注入”)。其中一个原因是您遇到的问题: testability

我建议你让WpManager取一个IInstallWpJobResult的实例(注意它是一个接口)作为其构造的一部分,而不是实例化它。通过这种方式,您可以轻松更改给定不同IInstallWpJobResult实现的类的行为,例如传递具有预定义行为的Mock<IInstallWpJobResult>以便于测试。

一旦开始使用依赖注入框架在运行时解析所有这些依赖项,这也会派上用场,因为它们通常会查看构造函数的参数,以了解要注入的依赖项。