说我有以下业务逻辑:
foreach (var item in repository.GetAll())
{
if (SomeConditition)
{
item.Status = Status.Completed;
repository.Update(item);
}
}
现在我写下面的单元测试:
public void Test()
{
var repository = new FakeRepository();
repository.Add(new Item());
RunBusinessLogic(repository);
Assert.AreEqual(Status.Completed, repository[0].Status);
}
FakeRepository在List上实现,GetAll()只返回列表。
虽然我可以使用这种方法测试大多数涉及的逻辑,但我无法验证我是否记得在业务代码中调用repository.Update()。由于FakeRepository.GetAll()返回实际对象,因此在调用Update()之前,业务代码已经修改了存储库对象。实际上,FakeRepository.Update()什么都不做。
我意识到我可以使用FakeRepository.Update来记录它已被调用,并在测试中断言。但是,如果我忘记调用Update,我也不能信任忘记更新,对吗?如果省略Update调用,我宁愿测试失败。
有什么想法吗?
答案 0 :(得分:3)
答案 1 :(得分:1)
我意识到我可以使用 FakeRepository.Update来记录它 它被称为,一种断言 考试。但如果我忘记打电话 更新,我不能信任 记得断言更新, 对?我更喜欢测试 如果更新调用是,则会失败 删去。
当您注意到您没有测试调用Update时,或者您注意到未调用Update时,那就是您编写一个调用Update的测试时。并不是说存储库中的项目已完成,而是调用了Update(这是一个不同的测试)。您已经决定调用Update非常重要,因此您需要对其进行测试。实现它的方法正如您所概述的那样 - 在FakeRepository中记录要更新的调用,并对其进行测试。
答案 2 :(得分:1)
有几件事可以单独进行单元测试:Repository.getAll()
和Repository.update()
方法,以及每个项目或每种项目的完成条件评估。我不确定我会在这里使用FakeRepository。
根据建议,另一种选择是让FakeRepository.update()
方法记录和/或计算更新次数。
但是如果我忘记调用Update,我也不能信任忘记更新,对吗?
正确,但是当你遵循TDD过程时,你将首先失败你的测试 - 红色 - 然后你编写代码让它通过 - 绿色。您将首先编写断言,导致测试失败,然后调用update()方法,使测试通过。
答案 3 :(得分:0)
鉴于尚未接受答案,并且答案是正确的(以我的拙见!),我可能会建议Tor Hovland可能会问一个微妙的不同问题:
具体来说,Tor可能会询问如何确保他的单元测试调用Update调用,并且在这些情况下单元测试应该失败。
如果是这种情况,有两件事需要说明:
首先,如果这很重要,请考虑在单元测试中将测试代码添加到TearDown()或适当的方法,但是这样做的问题在于它实际上没有测试应用程序代码是否正确 - 可能存在无法调用Update调用的应用程序代码。
如果有应用程序代码没有正确调用Update(),并且代码恰好依赖于它(谁知道为什么......也许代码有一个错误,恰好可以工作,因为它没有'调用Update?),并且开发人员修改库以便更改某些行为以便自动调用Update(),或者现在调用有问题的代码调用它,现在您的单元测试会执行功能更改不测试,因为他们总是调用更新。
因此,这导致需要说明的第二点 - 单元测试需要测试应用程序代码的作用。如果单元测试“不使用严格正确的设计意义上的代码”并不重要,重要的是单元测试测试代码本身的结果。换句话说,测试代码调用Update(),或者测试Update()的副作用是否存在。
要重新迭代,并重新回答我有点啰嗦的答案,不要测试测试。
答案 4 :(得分:0)
更好的方法是使用Dev Magic Fake,这样你就可以模拟数据库并且也可以是永久性的,你也可以模拟UI
只需添加对DevMagicFake.dll的引用
您可以编写以下代码:
[HttpPost]
public ActionResult Create(VendorForm vendorForm)
{
var repoistory = new FakeRepository<VendorForm>();
repoistory.Save(vendorForm);
return View("Page", repoistory.GetAll());
}
这会将VendorForm永久保存在内存中,您可以随时检索它。您还可以为此对象或模型中的任何其他对象生成数据,有关Dev Magic Fake的更多信息,请参阅CodePlex上的以下链接:< / p>
http://devmagicfake.codeplex.com
由于
M.Radwan