如何使用 Moq 验证调用类中的另一个方法

发布于 2024-08-04 19:05:31 字数 770 浏览 4 评论 0原文

这看起来很简单,但我似乎无法让它发挥作用。

我有一个带有 Save 方法的类,该方法仅调用另一个方法 ShouldBeCalled()。我想验证如果我调用 Save() ,另一个方法 ShouldBeCalled() 至少会执行一次。我想我可以做以下事情。

public class ClassA
{
    public virtual void Save()
    {
        ShouldBeCalled();
    }

    public virtual void ShouldBeCalled()
    {
        //This should get executed
    }
}

[TestFixture]
public class ClassA_Test
{
    [Test]
    public void Save_Should_Call_ShouldBeCalled()
    {
        var mockClassA = new Mock<ClassA>();
        mockClassA.Object.Save();

        mockClassA.Verify(x => x.ShouldBeCalled(), Times.AtLeastOnce());
    }
}

但我得到了异常“预期在模拟上调用至少一次,但从未执行过:x => x.ShouldBeCalled()”

这只是一个猜测,但 Moq 是否用它自己的版本覆盖 Save() 方法,该版本忽略我在真实对象的 Save() 方法中拥有的任何内容。

This seems like something simple but I can't seem to get it to work.

I have a class with a Save method that simply calls another method ShouldBeCalled(). I want to verify that if I call Save() that the other method ShouldBeCalled() is executed at least once. I thought that I could do the following.

public class ClassA
{
    public virtual void Save()
    {
        ShouldBeCalled();
    }

    public virtual void ShouldBeCalled()
    {
        //This should get executed
    }
}

[TestFixture]
public class ClassA_Test
{
    [Test]
    public void Save_Should_Call_ShouldBeCalled()
    {
        var mockClassA = new Mock<ClassA>();
        mockClassA.Object.Save();

        mockClassA.Verify(x => x.ShouldBeCalled(), Times.AtLeastOnce());
    }
}

But I get the exception "Expected invocation on the mock at least once, but was never performed: x => x.ShouldBeCalled()"

It is just a guess but Is Moq overriding the Save() method with it's own version which ignores anything I have inside the real object's Save() method.

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

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

发布评论

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

评论(4

宫墨修音 2024-08-11 19:05:31

您遇到这个问题是因为您正在嘲笑正在测试的内容。这没有道理。

您是正确的,Moq 将用自己的方法替换您的方法的实现。原因是您应该使用 Moq 来模拟您正在测试的类调用的内容,而不是您正在测试的类本身。

如果您的代码是这样设计的,则此测试将是合适的:

public class ClassA
{
    BusinessLogicClass bl;
    public ClassA(BusinessLogicClass bl)
    {
         this.bl = bl;
    }

    public void Save()
    {
        bl.ShouldBeCalled();
    }
}

public class BusinessLogicClass
{
    public virtual void ShouldBeCalled()
    {
        //This should get executed
    }
}

现在这是该方法的正确测试:

[TestFixture]
public class ClassA_Test
{
    [Test]
    public void Save_ShouldCallShouldBeCalled()
    {
        //Arrange
        var mockBLClass = new Mock<BusinessLogicClass>();
        mockBLClass.Setup(x => x.ShouldBeCalled()).Verifyable();

        //Act    
        ClassA classA = new ClassA(mockBLClass.Object);
        classA.Save();

        //Assert
        mockBLClass.VerifyAll();
    }
}

这里的关键教训是您模拟/存根您的测试需要运行的内容,而不是您的内容正在测试自己。

希望这有帮助,
安德森

You are having this problem because you are mocking what you are testing. This doesn't make sense.

You are correct that Moq will replace the implementation of your method with its own. The reason is you are supposed to use Moq to mock things the class you are testing calls, not the class you are testing itself.

This test would be appropriate if your code were designed thusly:

public class ClassA
{
    BusinessLogicClass bl;
    public ClassA(BusinessLogicClass bl)
    {
         this.bl = bl;
    }

    public void Save()
    {
        bl.ShouldBeCalled();
    }
}

public class BusinessLogicClass
{
    public virtual void ShouldBeCalled()
    {
        //This should get executed
    }
}

And here is the correct test of that method now:

[TestFixture]
public class ClassA_Test
{
    [Test]
    public void Save_ShouldCallShouldBeCalled()
    {
        //Arrange
        var mockBLClass = new Mock<BusinessLogicClass>();
        mockBLClass.Setup(x => x.ShouldBeCalled()).Verifyable();

        //Act    
        ClassA classA = new ClassA(mockBLClass.Object);
        classA.Save();

        //Assert
        mockBLClass.VerifyAll();
    }
}

The key lesson here is that you mock/stub what your test needs to run, not what you are testing itself.

Hope this helps,
Anderson

掐死时间 2024-08-11 19:05:31

尝试使用 CallBase = true,然后使用 false。我运行了你的代码并且它有效。

var mockClassA = new Mock<ClassA>();
mockClassA.CallBase = true;
mockClassA.Object.Save();
mockClassA.CallBase = false;
mockClassA.Verify(x => x.ShouldBeCalled(), Times.AtLeastOnce());

Try using the CallBase = true and then false. I ran your code and it works.

var mockClassA = new Mock<ClassA>();
mockClassA.CallBase = true;
mockClassA.Object.Save();
mockClassA.CallBase = false;
mockClassA.Verify(x => x.ShouldBeCalled(), Times.AtLeastOnce());
季末如歌 2024-08-11 19:05:31

是的,这是可以做到的。但是,您需要添加一行代码以使 Moq 跟踪 ShouldBeCalled 方法是否确实被调用。

类似下面的内容将会起作用:

var mockClassA = new Mock<ClassA>();
mockClassA.Setup(x => x.ShouldBeCalled()).Verifiable();    
mockClassA.Object.Save();    
mockClassA.Verify(x => s.ShouldBeCalled(), Times.AtLeastOnce());

Setup 方法设置期望。当您致电验证时,您是在要求起订量验证这些期望。如果您没有进行安装调用来创建 ShouldBeCalled 方法的期望,那么 Moq 不会认为它是可跟踪的,因此当您尝试验证它时会严重失败。

Yes, this can be done. However, you need to add a line of code to have Moq track whether or not the ShouldBeCalled method was indeed called.

Something like the following will work:

var mockClassA = new Mock<ClassA>();
mockClassA.Setup(x => x.ShouldBeCalled()).Verifiable();    
mockClassA.Object.Save();    
mockClassA.Verify(x => s.ShouldBeCalled(), Times.AtLeastOnce());

The Setup method sets up expectations. When you call Verify, you are asking Moq to verify these expectations. If you don't make a Setup call to create expectations for the ShouldBeCalled method, then Moq doesn't consider it to be trackable and will therefore fail hard when you try to Verify it.

兮子 2024-08-11 19:05:31

您可以使用 CallBase

[TestFixture]
public class ClassA_Test
{
    [Test]
    public void Save_Should_Call_ShouldBeCalled()
    {
        // Arrange
        var mockClassA = new Mock<ClassA>();
        mockClassA.CallBase = true; // this will call real methods unless the method is mocked/stubbed. 
        mockClassA.Setup(a => a.ShouldBeCalled());

        // Act
        mockClassA.Save();

        // Assert
        mockClassA.Verify(a => a.ShouldBeCalled(), Times.Once());
    }
}

You can stub methods in the system under test using CallBase.

[TestFixture]
public class ClassA_Test
{
    [Test]
    public void Save_Should_Call_ShouldBeCalled()
    {
        // Arrange
        var mockClassA = new Mock<ClassA>();
        mockClassA.CallBase = true; // this will call real methods unless the method is mocked/stubbed. 
        mockClassA.Setup(a => a.ShouldBeCalled());

        // Act
        mockClassA.Save();

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