这可以用 Moq 来嘲笑吗?

发布于 2024-07-30 09:22:32 字数 2352 浏览 5 评论 0原文

我正在努力模拟一些外部依赖项,并且在一个第三方类中遇到了麻烦,该类在其构造函数中接收另一个第三方类的实例。 希望 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();
    }
}

这是我用来包装一个第三方类并允许其进行 Moq'd 的类:

public class MyClass
{
    private SomeLibraryClass _SLC;

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

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

以下是我正在使用的第三方类的两个示例(您无法编辑这些):

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));
    }
}

I am working on mocking some external dependencies and am having trouble with one 3rd party class that takes in it's constructor an instance of another 3rd party class. Hopefully the SO community can give me some direction.

I want to create a mock instance of SomeRelatedLibraryClass that takes in it's constructor a mock instance of SomeLibraryClass. How can I mock SomeRelatedLibraryClass this way?

The repo code...

Here is a Main method that I am using in my test console application.

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();
    }
}

Here is a class that I have used to wrap one third party class and allow it to be Moq'd:

public class MyClass
{
    private SomeLibraryClass _SLC;

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

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

Here are two examples of 3rd party classes I am working with (YOU CAN NOT EDIT THESE):

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));
    }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

怪异←思 2024-08-06 09:22:32

我建议使用 网关 模式。 创建一个接口 ISomeRelatedLibraryClassGateway,而不是直接依赖于 SomeRelatedLibraryClass。 公开您需要使用 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 类实际上并不需要单元测试; 它所做的只是传递呼叫。 它确实需要在功能测试中进行测试,但是您可以在没有模拟的情况下进行功能测试。

希望这可以帮助。

I would suggest using the Gateway pattern. Rather than depend directly on SomeRelatedLibraryClass, create an interface ISomeRelatedLibraryClassGateway. Expose all of SomeRelatedLibraryClass' methods that you need to call with methods of the same signature on ISomeRelatedLibraryClassGateway.

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

Then create an implementation that routes all calls to the third party class:

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

  void ISomeRelatedLibraryClassGateway.WriteMessage(string message) {
    srlc.WriteMessage(message);
  }
}

Now the classes in your app that would depend on SomeRelatedLibraryClass can now depend on ISomeRelatedLibraryClassGateway instead, and this interface is easy to mock. The class SomeRelatedLibraryClassGateway doesn't really need unit tests; all it does is pass calls through. It does need to be tested in a functional test, but you can do functional testing without mocks.

Hope this helps.

贩梦商人 2024-08-06 09:22:32

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

AFAIK, if the class you're trying to mock out isn't virtual or an interface - you can't mock it with Moq. If your 3rd party library doesn't implement their classes, I think you're out of luck.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文