【问题标题】:C# testing - mock class in contructor callC# 测试 - 构造函数调用中的模拟类
【发布时间】:2020-02-15 16:37:57
【问题描述】:

我不熟悉在 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的构造函数?

【问题讨论】:

标签: c# unit-testing moq xunit


【解决方案1】:

我认为您可能需要稍微修改您的代码。您会看到,当从代码的其他部分实例化时,单独获取接口的模拟不会自动改变其他实现的行为方式。您通常希望通过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 或花哨的反射技术。但是,要违背似乎是社区接受的最佳实践,可能需要付出很多努力。

【讨论】:

    【解决方案2】:

    您在模拟依赖项的方向上是正确的,但是您缺乏依赖倒置原则的实现。

    使用您的代码原样,您将 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();
          ...
       }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-07-01
      • 1970-01-01
      • 2021-09-29
      • 1970-01-01
      • 1970-01-01
      • 2014-10-05
      相关资源
      最近更新 更多