gpt4 book ai didi

unit-testing - 状态/交互测试和混淆(或滥用)它们

转载 作者:行者123 更新时间:2023-12-04 05:28:20 25 4
gpt4 key购买 nike

我认为了解基于状态/交互的测试的定义(阅读 Fowler 的内容等)。我发现我开始基于状态,但一直在做更多基于交互的事情,我对如何测试某些事情感到有些困惑。

我在 MVC 中有一个 Controller ,一个 Action 调用一个服务来拒绝一个包:

public ActionResult Deny(int id)
{
service.DenyPackage(id);

return RedirectToAction("List");
}

这对我来说似乎很清楚。提供一个模拟服务,验证它被正确调用,完成。

现在,我有一个 View 操作,允许用户将证书与包关联:
public ActionResult Upload(int id)
{
var package = packageRepository.GetPackage(id);
var certificates = certificateRepository.GetAllCertificates();

var view = new PackageUploadViewModel(package, certificates);

return View(view);
}

这个我有点难住了。我正在做 Spec 样式测试(可能不正确),所以为了测试这个方法,我有一个类,然后有两个测试:验证包存储库被调用,验证证书存储库被调用。我实际上想要第三个来测试以验证构造函数是否被调用,但不知道如何做到这一点!我的印象是这是完全错误的。

因此,对于基于状态的测试,我会传入 id,然后测试 ActionResult 的 View 。好吧,这是有道理的。但是我不会对 PackageUploadViewModel 构造函数进行测试吗?因此,如果我对构造函数进行测试,那么我的一部分只想验证我调用了构造函数并且操作返回与构造函数返回的内容相匹配。

现在,我能想到的另一个选择是我有一个依赖于两个存储库的 PackageUploadViewModelBuilder(或同样愚蠢的名字),然后我只是将 id 传递给 CreateViewModel 方法或其他东西。然后我可以模拟这个对象,验证一切,然后开心。但是……嗯……好像很奢侈。我正在做一些简单的事情……不简单。另外,controller.action(id) 返回 builder.create(id) 似乎无缘无故地添加了一个层( Controller 负责构建 View 模型......对吧?)

我不知道......我认为更多基于状态的测试是必要的,但我担心如果我开始测试返回值然后如果方法 A 可以在 8 个不同的上下文中被调用我将有很多测试爆炸的重复。我一直在使用基于交互的测试将其中一些上下文传递给方法 B,这样我所要做的就是验证称为方法 B 的方法 A,并且我对方法 B 进行了测试,因此方法 A 可以相信这些上下文已被处理。因此,基于交互的测试正在构建这种测试层次结构,但基于状态的测试会将其扁平化一些。

我不知道这是否有意义。

哇,好长……

最佳答案

我认为 Roy Osherove 最近推特说,根据经验,你的测试应该 95% 基于状态,5% 基于交互。我同意。

最重要的是你的 API 做你想做的,这就是你需要测试的。如果你测试它如何实现它需要做的事情的机制,你很可能最终会遇到过度指定的测试,这会在可维护性方面咬你。

在大多数情况下,您可以设计您的 API,使基于状态的测试成为自然的选择,因为这要容易得多。

检查您的上传示例:调用 GetPackage 和 GetAllCertificates 是否重要?这真的是 Upload 方法的预期结果吗?

我猜不会。我的猜测是 Upload 方法的目的 - 这是存在的原因 - 是填充和提供正确的 View 。

因此,基于状态的测试将检查返回的 ViewResult 及其 ViewModel 并验证它是否具有所有正确的值。

当然,就目前的代码而言,您需要为 packageRepository 和 certificateRepository 提供测试替身,否则将抛出异常,但看起来调用存储库方法本身并不重要。

如果您对存储库使用 Stubs 而不是 Mocks,则您的测试不再与内部实现细节相关联。如果您稍后决定更改 Upload 方法的实现以使用包的缓存实例(或其他),则不会调用 Stub,但这没关系,因为无论如何它都不重要 - 重要的是返回的 View 包含预期数据。

即使所有返回的数据都是应该的,这也比测试中断更可取。

有趣的是,您的 Deny 示例看起来仍然是基于交互的测试的主要示例,因为只有通过检查间接输出,您才能验证该方法是否执行了正确的操作(DenyPackage 方法返回 void)。

所有这些以及更多内容,在优秀的书籍 xUnit Test Patterns 中得到了很好的解释。 .

关于unit-testing - 状态/交互测试和混淆(或滥用)它们,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1300221/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com