3

我正在模拟一些外部依赖项,并且在一个第 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));
    }
}
4

2 回答 2

10

我建议使用网关模式。与其直接依赖 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 类并不真正需要单元测试;它所做的只是传递呼叫。它确实需要在功能测试中进行测试,但是您可以在没有模拟的情况下进行功能测试。

希望这可以帮助。

于 2009-08-03T02:56:28.003 回答
2

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

于 2009-08-03T02:36:32.677 回答