在模拟对象上使用 Moq 验证间接调用的方法

发布于 2024-12-05 03:15:27 字数 350 浏览 0 评论 0原文

我的应用程序有一个 ProviderFactory 静态类,它具有传回记录器等静态实例的静态实用方法。然后,我的应用程序的其余部分可以从任何地方获取对记录器的引用,而无需传入记录器(常见的设计实践)。

因此,我的应用程序的另一部分 DbCacheProvider 具有调用记录器的方法,因此它在内部从工厂获取对记录器的引用,然后对其发出调用。

我的问题是,使用 Moq,我想验证记录器上的方法是否由 DbCacheProvider 中的方法调用。当我将模拟记录器作为参数传递到 DbCacheProvider 时,我可以使用依赖项注入来执行此操作,但我没有传递记录器(我不想这样做)。那么,我如何验证 DbCacheProvider 是否正在调用记录器?

My app has a ProviderFactory static class that has static utility methods passing back static instances of things like a logger. The rest of my app then can just grab a/the reference to the logger from anywhere without having to pass in the logger (common design practice).

So, another part of my app, the DbCacheProvider, has methods that make calls to the logger so internally it gets a reference to the logger from the factory and then issues calls to it.

My question is that using Moq, I want to verify methods on the logger are being called by the methods within the DbCacheProvider. I can do this using dependency injection when I pass a mock logger into the DbCacheProvider as a parameter, but I'm not passing the logger in (not do I want to). So, how would I verify the DbCacheProvider is making calls to the logger?

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

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

发布评论

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

评论(2

烙印 2024-12-12 03:15:27

如果您不想通过构造函数传递记录器,则需要在运行单元测试时更改 ProviderFactory 以返回模拟的记录器。

无论如何,经常建议设置依赖项注入有几个原因:

  1. 您的测试更直接,并且不涉及自定义工厂
  2. IoC 框架(如 Unity、Ninject 和 Autofac)可以在设置依赖项时轻松创建对象这边走。如果您以这种方式设置所有对象,框架将完成创建正确对象并将其传递给您的所有繁重工作。依赖注入是自动完成的,不会给您带来负担。

If you don't want to pass the logger in through the constructor you'd need to change your ProviderFactory while running unit tests to return your mocked logger.

Anyway there are a couple of reasons it's often suggested to set up dependency injection:

  1. Your tests are more straightforward and don't involve finagling with custom factories
  2. IoC frameworks like Unity, Ninject and Autofac make it easy to create objects when their dependencies are set up this way. If you set up all of your objects this way, the framework will do all the heavy lifting of creating the right objects and passing them in for you. The dependency injection is done automatically and won't be a burden for you.
面犯桃花 2024-12-12 03:15:27

没有答案的老问题,我有一个类似的问题并这样解决:

我有以下示例代码,需要验证不仅调用了一个方法,而且还调用了一个特定的值。

public interface ILog
{
    void Info(string message);
}

public interface ILogFactory
{
    ILog GetLogger();
}

这是正在测试的类,其中正在注入接口项:

public class NewAction
{
    readonly ILogFactory _logger;

    public NewAction(ILogFactory logger)
    {
        _logger = logger;
    }

    public void Step1()
    {
        _logger.GetLogger().Info("Step 1");
    }

    public void Step2()
    {
        _logger.GetLogger().Info("Step 2");
    }
}

这显然是我的实际代码的非常简单的视图,但我需要验证 Step1 和 Step2 的行为是否符合预期并将正确的值传递给日志,这这意味着我还需要确保它们以正确的顺序发生。我的测试:

[TestClass]
public class UnitTest1
{
    [TestMethod]
    public void TestMethod1()
    {
        // Arrange
        var log = new Mock<ILog>();

        var factory = new Mock<ILogFactory>();
        factory.Setup(l => l.GetLogger()).Returns(log.Object);

        // Act
        var action = new NewAction(factory.Object);
        action.Step1();
        action.Step2();

        // Assert
        factory.Verify(l => l.GetLogger());
        log.Verify(l => l.Info(It.Is<string>(s => s == "Step 1")));
        log.Verify(l => l.Info(It.Is<string>(s => s == "Step 2")));
    }
}

希望这有帮助。

Old question without an answer, I had a similar problem and solved it like this:

I have the following sample code and need to verify that not only was a method called but was called with a specific value.

public interface ILog
{
    void Info(string message);
}

public interface ILogFactory
{
    ILog GetLogger();
}

This is the class being tested, where the interface items are being injected:

public class NewAction
{
    readonly ILogFactory _logger;

    public NewAction(ILogFactory logger)
    {
        _logger = logger;
    }

    public void Step1()
    {
        _logger.GetLogger().Info("Step 1");
    }

    public void Step2()
    {
        _logger.GetLogger().Info("Step 2");
    }
}

This is obviously a very simplistic view of my actual code, but I needed to verify that Step1 and Step2 are behaving as expected and passed the correct values to the Log, this would mean I also needed to ensure they occurred in the right order. My test:

[TestClass]
public class UnitTest1
{
    [TestMethod]
    public void TestMethod1()
    {
        // Arrange
        var log = new Mock<ILog>();

        var factory = new Mock<ILogFactory>();
        factory.Setup(l => l.GetLogger()).Returns(log.Object);

        // Act
        var action = new NewAction(factory.Object);
        action.Step1();
        action.Step2();

        // Assert
        factory.Verify(l => l.GetLogger());
        log.Verify(l => l.Info(It.Is<string>(s => s == "Step 1")));
        log.Verify(l => l.Info(It.Is<string>(s => s == "Step 2")));
    }
}

Hope this helps.

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