C#测试-构造函数调用中的模拟类

时间:2020-02-15 16:37:57

标签: c# unit-testing moq xunit

我是在Visual Studio 2019中将MoqXunit结合使用的新手。

我想模拟在我测试过的类的构造函数中调用的类的构造函数调用。 我的问题的简单演示:

public class MockedClass : IMockedClass
{
   public MockedClass()
   {
      // don't call this
   }
   public List<string> Function1()
   { /* return a List<string> here */ }
}
public class MyClass
{
   readonly IMockedClass mockedClass = null;
   public MyClass()
   {
      mockedClass = new MockedClass();
   }
   public string Function2()
   { /* return a string here */ }
}
public class MyClassTest
{
   [Fact]
   public string Function2Test()
   {
      var returnMock = new List<string>() { "1", "2", "3" };
      var mockMockedClass = new Mock<IMockedClass>();
      mockMockedClass.Setup(x => x.Function1()).Returns(returnMock);
      var myClass = new MyClass();
      var result = myClass.Function2();
      ...
   }
}

我的问题是,在测试Function2Test中,正在调用MyClass的构造函数,该构造函数调用MockedClass的构造函数。 但是我不希望调用MockedClass的构造函数。

如何模拟MockedClass的构造函数?

2 个答案:

答案 0 :(得分:3)

我认为您可能需要稍微修改代码。您会看到,从接口的其他部分实例化接口本身本身并不会自动更改其他实现的行为。通常,您希望通过Dependency Injection将模拟的实现注入经过测试的代码中。

public class MyClass
{
    readonly IMockedClass mockedClass = null;
    public MyClass(IMockedClass c)
    {
        mockedClass = c; // now you'll get the correct implemetation
    }
    public string Function2()
    { /* return a string here */ }
}
void Main()
{

        var returnMock = new List<string>() { "1", "2", "3" };
        var mockMockedClass = new Mock<IMockedClass>(); // get your mock here
        mockMockedClass.Setup(x => x.Function1()).Returns(returnMock);
        var myClass = new MyClass(mockMockedClass.Object); // inject it here
        var result = myClass.Function2();
}

然后,您将需要设置您的依赖注入容器,以便在实际应用程序代码运行时为您提供具体的MockedClass。根据您的代码和要求,有heaps of options,因此在这里我不建议使用特定的框架。

从理论上讲,您也许可以在当前代码结构中模拟该类。我有可能看到您选择Fakes还是奇特的反射技术。但是,这可能会成为与社区公认的最佳实践背道而驰的方法。

答案 1 :(得分:1)

您在模拟依赖关系的正确方向上,但是缺少依赖关系反转原理的实现。

照原样使用代码,将MyClass绑定到MockedClass,并且进一步让MyClass控制MockedClass对象的生存期。

您应该做的是更改MyClass的构造函数以接受IMockedClass对象。请注意,您应该传递接口,而不是类类型。

public class MyClass
{
   readonly IMockedClass mockedClass = null;
   public MyClass(IMockedClass mockedClass)
   {
      this.mockedClass = mockedClass();
   }
   public string Function2()
   { /* return a string here */ }
}

,您的测试代码将是:

public string Function2Test()
   {
      var returnMock = new List<string>() { "1", "2", "3" };
      var mockMockedClass = new Mock<IMockedClass>();
      mockMockedClass.Setup(x => x.Function1()).Returns(returnMock);
      var myClass = new MyClass(mockMockedClass.Object);
      var result = myClass.Function2();
      ...
   }