【问题标题】:Can this be mocked with Moq?这可以用 Moq 来嘲笑吗?
【发布时间】:2009-08-03 02:16:50
【问题描述】:

我正在模拟一些外部依赖项,并且遇到了一个第 3 方类的问题,该类将其构造函数作为另一个第 3 方类的实例。希望 SO 社区能给我一些指导。

我想创建一个SomeRelatedLibraryClass 的模拟实例,它在它的构造函数中接收一个SomeLibraryClass 的模拟实例。我怎样才能以这种方式模拟SomeRelatedLibraryClass

回购代码...

这是我在测试控制台应用程序中使用的 Main 方法。

public static void Main()
{
    try
    {
        SomeLibraryClass slc = new SomeLibraryClass("direct to 3rd party");
        slc.WriteMessage("3rd party message");
        Console.WriteLine();

        MyClass mc = new MyClass("through myclass");
        mc.WriteMessage("myclass message");
        Console.WriteLine();

        Mock<MyClass> mockMc = new Mock<MyClass>("mock myclass");
        mockMc.Setup(i => i.WriteMessage(It.IsAny<string>()))
            .Callback((string message) => Console.WriteLine(string.Concat("Mock SomeLibraryClass WriteMessage: ", message)));

        mockMc.Object.WriteMessage("mock message");
        Console.WriteLine();
    }
    catch (Exception e)
    {
        string error = string.Format("---\nThe following error occurred while executing the snippet:\n{0}\n---", e.ToString());
        Console.WriteLine(error);
    }
    finally
    {
        Console.Write("Press any key to continue...");
        Console.ReadKey();
    }
}

这是我用来包装一个第三方类并允许它最小起订量的类:

public class MyClass
{
    private SomeLibraryClass _SLC;

    public MyClass(string constructMsg)
    {
        _SLC = new SomeLibraryClass(constructMsg);
    }

    public virtual void WriteMessage(string message)
    {
        _SLC.WriteMessage(message);
    }
}

以下是我正在使用的第 3 方课程的两个示例(您不能编辑这些):

public class SomeLibraryClass
{
    public SomeLibraryClass(string constructMsg)
    {
        Console.WriteLine(string.Concat("SomeLibraryClass Constructor: ", constructMsg));
    }

    public void WriteMessage(string message)
    {
        Console.WriteLine(string.Concat("SomeLibraryClass WriteMessage: ", message));
    }
}

public class SomeRelatedLibraryClass
{
    public SomeRelatedLibraryClass(SomeLibraryClass slc)
    {
        //do nothing
    }

    public void WriteMessage(string message)
    {
        Console.WriteLine(string.Concat("SomeRelatedLibraryClass WriteMessage: ", message));
    }
}

【问题讨论】:

    标签: c# .net unit-testing mocking moq


    【解决方案1】:

    我建议使用Gateway 模式。与其直接依赖 SomeRelatedLibraryClass,不如创建一个接口 ISomeRelatedLibraryClassGateway。在 ISomeRelatedLibraryClassGateway 上使用具有相同签名的方法公开您需要调用的所有 SomeRelatedLibraryClass' 方法。

    public interface ISomeRelatedLibraryClassGateway {
      void WriteMessage(string message);
    }
    

    然后创建一个将所有调用路由到第三方类的实现:

    public class SomeRelatedLibraryClassGateway : ISomeRelatedLibraryClassGateway {
      private readonly SomeRelatedLibraryClass srlc;
      public SomeRelatedLibraryClassGateway(SomeRelatedLibraryClass srlc) {
        this.srlc = srlc;
      }
    
      void ISomeRelatedLibraryClassGateway.WriteMessage(string message) {
        srlc.WriteMessage(message);
      }
    }
    

    现在,您的应用中依赖 SomeRelatedLibraryClass 的类现在可以依赖 ISomeRelatedLibraryClassGateway,而且这个接口很容易模拟。 SomeRelatedLibraryClassGateway 类并不真正需要单元测试;它所做的只是传递呼叫。 确实需要在功能测试中进行测试,但您可以在没有模拟的情况下进行功能测试。

    希望这会有所帮助。

    【讨论】:

    • 实际上问题是我需要模拟 SomeRelatedLibraryClass 作为 SomeLibraryClass 类型的参数。我不清楚网关模式如何让我更轻松地模拟该类。在集成外部依赖项时,我通常会使用网关模式,但对于这个示例,我省略了接口定义和实现,因为我认为它与问题无关。
    • 重点是避免模拟 SomeRelatedLibraryClass。使用网关模式可以避免模拟 SomeRelatedLibraryClass,因为(大部分)您的代码并不直接依赖它。这是一个重构代码的示例,以便于测试。
    【解决方案2】:

    AFAIK,如果您尝试模拟的类不是虚拟的或接口 - 您无法使用 Moq 模拟它。如果您的 3rd 方库没有实现他们的类,我认为您不走运。

    【讨论】:

      猜你喜欢
      • 2021-09-29
      • 1970-01-01
      • 2012-07-26
      • 2018-01-13
      • 2017-11-20
      • 2020-03-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多