无法弄清楚为什么这个犀牛模拟失败了?错误:预期为真,但是:错误

时间:2010-09-09 21:41:13

标签: c# rhino-mocks rhino

以下是代码:

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

3 个答案:

答案 0 :(得分:4)

你不应该嘲笑你正在测试的课程。你应该只是模拟被测试的类所依赖的类。像这样:

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

答案 1 :(得分:0)

我同意tvanfosson的回答。 99%(可能是100%)的时间,你不会想要你的SUT模拟。

然而,它失败的原因是因为你的电话:

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

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

修改

如果不清楚,那意味着BackHaulMaximumReached()将(我认为)返回其返回类型的默认值,在bools的情况下为“false”。所以你需要将该方法存根以返回true以使Assert.AreEqual传递(这不是我所说的好测试)。

你的下一个断言将失败,因为EmailNetworkProvider()永远不会被调用(再次,因为你正在调用mock的方法,而不是实际的SUT方法)。

答案 2 :(得分:0)

我会按如下方式更改代码:

    //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()断言所有期望都是根据规定的设置发生的。