我应该测试我的控制器(MVC)吗?

Posted

技术标签:

【中文标题】我应该测试我的控制器(MVC)吗?【英文标题】:Should I test my controllers (MVC)? 【发布时间】:2012-04-29 22:31:12 【问题描述】:

我已经使用 TDD 几个月了,现在我想学习如何测试我的控制器 (MVC)。

单元测试是通过测试每个功能的最小单元来进行的。有时,控制器并不小。它们从模型中获取数据,然后传递给视图。

我应该如何对控制器进行单元测试?我应该模拟控制器的依赖项吗?

控制器测试是否被视为集成测试?

谢谢。

【问题讨论】:

【参考方案1】:

我做 TDD 已经很长时间了。我用 ASP.NET MVC 做 TDD 已经一年多了。

我从规范规则开始:“没有单元测试就没有代码行”,所以我测试了所有内容 - 包括控制器。控制器必须经过测试,这是 MVC 框架的目标之一 - 使这些东西可测试。

对于小型应用程序,这种方法非常有效。几乎所有的逻辑都放在控制器中,一切都经过了很好的测试。

但只要我继续使用 MVC,我就开始改变主意。我尽量让控制器保持纤薄。理想情况下,仅将调用委托给某个业务对象并包装结果。剩下的就是过滤器了。

这对我也很有效!我现在拥有单独实现/测试的业务对象,因此控制器只是集成点。没有理由测试集成点,因为它太小了。

关于集成测试:我还没有遇到我真正需要的情况。不要忘记,控制器总是依赖于构造函数注入的抽象。只要您对这些抽象如何工作有“好的”假设,您就可以创建适当的单元测试。当你失败时,你只需更正单元测试。

集成测试很重要也很有用,但我尝试尽可能少地创建这些测试。

【讨论】:

您先编写模型的测试,对吗?你什么时候写集成测试?可以举个例子吗?【参考方案2】:

我对控制器采用与 Alexander B 相同的方法。我的控制器又薄又笨。但是,我仍然为它们编写测试,以确保它们正确调用业务或服务对象并传递正确的参数。

我上周终于发现的一个实际错误可能最好地说明了这一点。我有一个控制器,允许经理批准或拒绝来自用户的请求,它有两个视图,一个未完成请求的列表视图和一个每个请求的详细信息视图。两种视图都可以批准或拒绝。控制器调用的服务有许多其他公开的方法,包括一个用于更改请求状态的方法……您可以看到它的去向。列表视图调用正确的方法来批准或拒绝并触发工作流,详细视图只调用更改状态方法,并没有启动任何进一步的工作流。这是我的编码错误,但在我的一生中,我很久都看不到它了——工作流在后台线程中运行,我花了一周的时间在这些线程中运行,假设这是该部分中的错误。

对我来说

一旦您的控制器将数据传递到其他地方,它就需要进行测试。 如果您的控制器检查模型有效性,它需要测试(如果 有人拿走了支票?)

等等

【讨论】:

【参考方案3】:

昨天问了同样的问题:

Does it make sense to test controllers

在我看来 - 是的,测试控制器确实有意义。你可以:

在它们后面模拟服务,因此只测试控制器本身更容易 不模拟服务并进行集成测试

【讨论】:

应用服务aspnetboilerplate.com/Pages/Documents/…【参考方案4】:

要为您的控制器开发单元测试,自然的方法是模拟控制器所依赖的接口(它控制的“事物”,我们称它们为IControllables)。然后您可以验证控制器是否以预期的方式操作受控对象。

如果控制器和受控对象之间的交互很复杂,那么专用的集成测试可能是有意义的。例如,可能有一系列实现IControllable 的类——这些实现中的每一个都能与控制器很好地协同工作吗?也许多个不同的IControllables 会交互(使用相同的资源)?或者IControllables 可能有一些棘手的方法来配置它们,从而影响它们的行为?对此进行测试的一种方法是编写一个可重用的测试套件,您可以在其中注入一系列可疑的IControllable 实现或它们的组合。

最后但同样重要的是,TDD 也是关于验收测试。因此,在进行 TDD 时,您还将进行高级端到端测试来执行最终用户会识别的场景。最有可能的是,这些也将锻炼控制器 - 通过这种方式还可以测试您的控制器和(某些)类之间的正确集成。

【讨论】:

以上是关于我应该测试我的控制器(MVC)吗?的主要内容,如果未能解决你的问题,请参考以下文章

我应该从 MVC 框架中的控制器或模型中调用 redirect() 吗?

在 PHP 中使用 MVC 时,1 控制器应该能够加载整个动态用户配置文件吗?

MVC - 我需要在视图中使用控制器吗?

PHPUnit - 使用 $_POST 变量测试 MVC 控制器

ASP/NET MVC:带会话的测试控制器?嘲讽?

在 ASP.NET MVC 3 中的多个服务之间共享一个工作单元