代码之家  ›  专栏  ›  技术社区  ›  Xaisoft

不明白为什么这个犀牛模型失败了?错误:应为true,但为:false

  •  -1
  • Xaisoft  · 技术社区  · 14 年前

    代码如下:

    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 回复  |  直到 14 年前
        1
  •  4
  •   tvanfosson    14 年前

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

    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();
    }
    
        2
  •  0
  •   Phil Sandler    14 年前

    我同意Tvanfosson的回答。99%(也许100%)的时候,你不会想要一个模拟你的SUT。

    但是,失败的原因是您的呼叫:

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

    将导致实际方法backhaulMaximumReached()被调用!它将调用模拟方法。

    编辑

    如果不清楚,这意味着backhaulMaximumReached()将(我认为)返回其返回类型的默认值,对于bools,该值为“false”。因此,您需要去掉该方法以返回true,以使assert.areequal通过(正如我所说,这不是一个好的测试)。

    然后,您的下一个断言将失败,因为永远不会调用emailNetworkProvider()(再次,因为您调用的是模拟方法,而不是实际的SUT方法)。

        3
  •  0
  •   KeithS    14 年前

    我将更改代码如下:

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

    您所期望的是,给定类的输入,当您调用一个方法时,还会调用另一个导致一些不必要的副作用的方法。你想模仿副作用诱导行为,但你想练习剩下的实际逻辑。

    解决方案是一个局部块。它允许模拟行为仅应用于您指定的模拟类的成员。您可以在多个语法中使用它,但是最安全、最可靠的方法是记录和回放预期,而不是在模拟上调用expects()方法。

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