以下是代码:
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());
}
答案 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()断言所有期望都是根据规定的设置发生的。