无法弄清楚为什么这个 Rhino Mock 失败了?错误:预期为真,但实际为:错误

发布于 2024-09-19 02:00:55 字数 878 浏览 11 评论 0原文

这是代码:

public interface IAccessPoint
{
    int BackHaulMaximum { get; set; }

    bool BackHaulMaximumReached();
    void EmailNetworkProvider();
}

public class AccessPoint : IAccessPoint
{

    public int BackHaulMaximum { get; set; }

    public bool BackHaulMaximumReached()
    {
        if (BackHaulMaximum > 80)
        {
            EmailNetworkProvider();
            return true;
        }
        return false;
        }

    public void EmailNetworkProvider()
    {

    }
}

//Test
[Test]
public void NetworkProviderShouldBeEmailedWhenBackHaulMaximumIsReached()
{
        var apMock = MockRepository.GenerateMock<IAccessPoint>();

        apMock.Stub(x => x.BackHaulMaximum).Return(81);

        Assert.AreEqual(true, apMock.BackHaulMaximumReached());

        apMock.AssertWasCalled(x => x.EmailNetworkProvider());
 }

Here is the code:

public interface IAccessPoint
{
    int BackHaulMaximum { get; set; }

    bool BackHaulMaximumReached();
    void EmailNetworkProvider();
}

public class AccessPoint : IAccessPoint
{

    public int BackHaulMaximum { get; set; }

    public bool BackHaulMaximumReached()
    {
        if (BackHaulMaximum > 80)
        {
            EmailNetworkProvider();
            return true;
        }
        return false;
        }

    public void EmailNetworkProvider()
    {

    }
}

//Test
[Test]
public void NetworkProviderShouldBeEmailedWhenBackHaulMaximumIsReached()
{
        var apMock = MockRepository.GenerateMock<IAccessPoint>();

        apMock.Stub(x => x.BackHaulMaximum).Return(81);

        Assert.AreEqual(true, apMock.BackHaulMaximumReached());

        apMock.AssertWasCalled(x => x.EmailNetworkProvider());
 }

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

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

发布评论

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

评论(3

泪眸﹌ 2024-09-26 02:00:56

我同意tvanfosson的回答。 99%(也许 100%)的情况下,您不会想要为您的 SUT 进行模拟。

然而,它失败的原因是因为您的调用:

Assert.AreEqual(true, apMock.BackHaulMaximumReached()); 

不会将导致调用实际方法 BackHaulMaximumReached() !它将调用模拟的方法。

编辑

如果不清楚,这意味着 BackHaulMaximumReached() 将(我认为)返回其返回类型的默认值,在布尔值的情况下为“false”。因此,您需要删除该方法以返回 true 以使 Assert.AreEqual 能够通过(正如我所说,这不是一个好的测试)。

然后您的下一个断言将失败,因为 EmailNetworkProvider() 永远不会被调用(同样,因为您正在调用模拟的方法,而不是实际的 SUT 的方法)。

I agree with tvanfosson's answer. 99% (maybe 100%) of the time, you won't want a mock for your SUT.

However the reason it is failing is because your call:

Assert.AreEqual(true, apMock.BackHaulMaximumReached()); 

is not going to result in the actual method BackHaulMaximumReached() being called! It's going to call the mock's method.

Edit

If it wasn't clear, that means that BackHaulMaximumReached() will (I think) return the default value for its return type, which is "false" in the case of bools. So you need to stub out that method to return true to get the Assert.AreEqual to to pass (which is not a good test as I said).

Your next assertion will then fail, as EmailNetworkProvider() will never get called (again, because you are calling the mock's methods, not the actual SUT's methods).

百善笑为先 2024-09-26 02:00:56

我将更改代码如下:

    //Test
    [Test]
    public void NetworkProviderShouldBeEmailedWhenBackHaulMaximumIsReached()
    {

        var mockRepo = new MockRepository();
        var apMock = mockRepo.PartialMock<AccessPoint>();

        using (mockRepo.Record())
        {
            Expect.Call(apMock.EmailNetworkProvider).Repeat.Once();
        }
        using (mockRepo.Playback())
        {
            apMock.BackHaulMaximum = 81;
            Assert.AreEqual(true, apMock.BackHaulMaximumReached());
        }
        mockRepo.VerifyAll();
    }

您所期望的是,给定类的输入,当您调用一个方法时,还会调用另一个会引起一些不需要的副作用的方法。您想要模拟引起副作用的行为,但想要练习其余的实际逻辑。

解决方案是 PartialMock。它允许模拟行为仅应用于您指定的模拟类的成员。您可以在多种语法中使用它,但最安全、最可靠的方法是记录和回放期望,而不是在模拟本身上调用 Expects() 方法。

我们在这里使用它来期望调用我们想要模拟的方法;期望调用将导致实际方法不被调用。然后,执行该类,并使用实际类的逻辑(因此我们测试中的断言成功),但是当到达对我们预期方法的调用时,实际调用的是更新一些内部计数器的模拟方法。然后,VerifyAll() 断言所有期望都按照规定的设置发生。

I would change the code as follows:

    //Test
    [Test]
    public void NetworkProviderShouldBeEmailedWhenBackHaulMaximumIsReached()
    {

        var mockRepo = new MockRepository();
        var apMock = mockRepo.PartialMock<AccessPoint>();

        using (mockRepo.Record())
        {
            Expect.Call(apMock.EmailNetworkProvider).Repeat.Once();
        }
        using (mockRepo.Playback())
        {
            apMock.BackHaulMaximum = 81;
            Assert.AreEqual(true, apMock.BackHaulMaximumReached());
        }
        mockRepo.VerifyAll();
    }

What you're expecting is that given the input to the class, when you call a method, another method that induces some unwanted side effects is also called. You want to mock the side-effect-inducing behavior, but you want to exercise the rest of the actual logic.

The solution is a PartialMock. It allows the mocking behavior to be applied to only the members of the mocked class that you specify. You can use it in several syntaxes, but the safest, most reliable method is to record and playback expectations rather than call the Expects() method on the mock itself.

We are using it here to expect a call on our method that we want to mock; expecting the call will cause the actual method not to be called. Then, the class is exercised, and the logic of the actual class is used (hence the assertion in our test succeeds), but when the call to our expected method is reached, what is actually called is the mocked method that updates some internal counters. Then, VerifyAll() asserts that all expectations happened according to the settings prescribed.

深府石板幽径 2024-09-26 02:00:55

您不应该嘲笑您正在测试的类。您应该只模拟被测试类所依赖的类。像这样的东西:

public interface IAccessPoint
{
    int BackHaulMaximum { get; set; }

    bool BackHaulMaximumReached();
    void EmailNetworkProvider();
}

public class AccessPoint : IAccessPoint
{
    private IMailProvider Mailer { get; set; }

    public AccessPoint( IMailProvider provider )
    {
        this.Mailer = provider ?? new DefaultMailProvider();
    }

    public int BackHaulMaximum { get; set; }

    public bool BackHaulMaximumReached()
    {
        if (BackHaulMaximum > 80)
        {
            EmailNetworkProvider();
            return true;
        }
        return false;
        }

    public void EmailNetworkProvider()
    {
        this.Mailer.SendMail(...);
    }
}

[Test]
public void NetworkProviderShouldBeEmailedWhenBackHaulMaximumIsReached()  
{  
    var mailerMock = MockRepository.GenerateMock<IMailProvider>();  

    mailerMock .Expect( m => m.SendMail( ... specify argument matches ... ) ); 

    var accessPoint = new AccessPoint( mailerMock ); 

    accessPoint.BackHaulMaximum = 81;

    Assert.IsTrue( accessPoint.BackHaulMaximumReached() );

    mailerMock.VerifyAllExpectations();
}

You shouldn't be mocking the class that you are testing. You should only be mocking the classes that class under test depends on. Something like this:

public interface IAccessPoint
{
    int BackHaulMaximum { get; set; }

    bool BackHaulMaximumReached();
    void EmailNetworkProvider();
}

public class AccessPoint : IAccessPoint
{
    private IMailProvider Mailer { get; set; }

    public AccessPoint( IMailProvider provider )
    {
        this.Mailer = provider ?? new DefaultMailProvider();
    }

    public int BackHaulMaximum { get; set; }

    public bool BackHaulMaximumReached()
    {
        if (BackHaulMaximum > 80)
        {
            EmailNetworkProvider();
            return true;
        }
        return false;
        }

    public void EmailNetworkProvider()
    {
        this.Mailer.SendMail(...);
    }
}

[Test]
public void NetworkProviderShouldBeEmailedWhenBackHaulMaximumIsReached()  
{  
    var mailerMock = MockRepository.GenerateMock<IMailProvider>();  

    mailerMock .Expect( m => m.SendMail( ... specify argument matches ... ) ); 

    var accessPoint = new AccessPoint( mailerMock ); 

    accessPoint.BackHaulMaximum = 81;

    Assert.IsTrue( accessPoint.BackHaulMaximumReached() );

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