为什么要编写控制器的单元测试?


22

对我来说,这是完全不相关的单元测试,我不明白为什么有人会花时间编写它,因为从中获得的价值很小。如果此控制器通过在浏览器中执行该方法返回所需的类型,我会非常清楚。确实,您认为需要为此进行测试吗?为什么?

public class ConstituencyControllerTests
{
    private ConstituencyController _constituencyController;
    private Mock<IConstituencyService> _IConstituencyServiceMock;

    public ConstituencyControllerTests() {
        _IConstituencyServiceMock = new Mock<IConstituencyService>();
    }

    [Test]
    public async Task I_Check_For_Return_Type_And_Result() {
        _constituencyController = new ConstituencyController( _IConstituencyServiceMock.Object );

        var result = await _constituencyController.Get();
        var content = ( (dynamic)result ).Content;

        Assert.IsEmpty( content );
        Assert.IsInstanceOf( typeof( System.Web.Http.Results.OkNegotiatedContentResult<IEnumerable<ListOfConstituencies>> ), result );
        _IConstituencyServiceMock.Verify( x => x.ListOfConstituencies(), Times.Once() );
    }
}


7
不同意@gnat。这与语言构造无关,而与控制器返回的结果类型有关。当您没有继承层次结构时,它可能会归结为相同的事物,但是当控制器希望返回祖先时,它变成了完全不同的野兽,控制器返回了Person,现在Person被更改为不是继承于Ancestor,而是PeopleAncestor ...也回答了为什么测试这种方法可能是一个好主意...;)单元测试的目的是应对某些事物的变化会破坏其他事物的情况。
Marjan Venema


倾向于同意,我通常不花太多时间来测试应用程序的入口点。就像单元测试是控制台应用程序的主要方法一样。对我来说意义不大
Mvision

Answers:


29

他们的关键点在这里:

如果此控制器通过在浏览器中执行方法返回所需的类型,我会非常清楚

单元测试是关于自动化非回归测试简单的代码单元,而不是您自己看。您不想总是在应用程序中进行单元设置。

编辑:添加@anotherdave评论:

这与扩展的难易程度有关。在浏览器中测试一个控制器可能没问题;10、20、50个控制器呢?您只需编写一次测试;更换控制器时可能需要更新它,这是开销。但是,您多久部署一次?当然,每次进行检查时,手动检查的开销都要大得多

作为@Vladislav答案的替代方法,对所有内容进行单元测试绝对是过大的,并且确实是不受欢迎的。如果您需要更轻的东西,可以使用Selenium进行更高级别的非回归测试。当然,您获得的覆盖范围比单元测试要少,但是您可以获得合理的覆盖范围,从而减少了进行单元测试的时间,并且更加灵活。

也就是说,如果您对所有内容进行单元测试,则每次修改一个简单元素时都必须更新一个或多个测试。


4
还要补充I would know perfectly well if this controller returned the wanted type by executing the method in a browser.一下:—这是易于扩展的。在浏览器中测试一个控制器可能没问题;10、20、50个控制器呢?您只需编写一次测试;更换控制器时可能需要更新它,这是开销。但是,您多久部署一次?当然,每次进行检查时,人工检查肯定会比测试多得多。
anotherdave '16

“单元测试与自动化有关”-正确,但是集成测试(Selenium / Webdriver / etc。)也是如此。我不认为单元测试比集成测试要快实施就不必花很多时间。很大程度上取决于方法,但是,如果要获得有效的单元测试,需要模拟出十二种不同的服务并在每个服务中进行调用,则集成测试可能会更快地实现且更易于维护(尽管通常运行起来要慢得多,是的) 。关键在于,很大程度上取决于上下文和被测代码的复杂性。
aroth

@anotherdave添加了评论
Walfrat '16

@aroth我的观点相反,完整的单元测试代码需要花费大量时间,并且如果不进行某些单元测试的更改,则很难更改代码。集成测试更轻松。当然,您需要对非常复杂的东西进行单元测试,但这并不是因为您对该部分进行了单元测试,所以您必须对所有内容进行单元测试。再一次,我们看到人们在寻找不存在他的银弹。
Walfrat

24

为什么要编写控制器的单元测试?

因为在不了解上下文的情况下无法确定是否需要测试。以下是一些您可能要测试控制器的原因:

  • 控制器可能包含复杂的服务接线逻辑,容易出错。服务本身可能运行良好,这是您要测试的结果,并且出于某些原因,您考虑不将业务流程层引入应用程序中
  • 您的控制器包含应用程序的全部业务逻辑,并且实际上您可以测试所有控制器(请不要假装自己一生都在使用理想的代码库,请相信我)
  • 您的团队由99%的天才和1%的平均水平的人组成,并且您希望将这1%的薪水中的错误排除在外

2
我要补充一点:“您无法预见将来会有谁摆脱该项目,而测试是自我记录代码的一部分”
Laiv 2016年

4
到中间点,除了没有模拟的控制器测试之外,在没有考虑测试的情况下创建的项目可能无法进行其他测试。我与一个C#团队合作,他们的工作就是这样一个项目,因此他们正在编写控制器测试,直到他们可以添加必要的结构(接口等)以能够进行更细粒度的测试为止。
韦恩·康拉德

1

我完全同意OP。

控制器的单元测试毫无意义。您可以通过回归测试隐式测试控制器(例如,使用Selenium)。

您应该TDD控制器使用的所有组件/对象,并使控制器尽可能地薄。然后,所有内容均经过正确的单元测试。您想确定的是,在执行Web请求时,一切都可以很好地协同工作。那就是回归测试。


也许是这样,但这并不是问题的答案。实际上,这里反对使用单元测试。
JᴀʏMᴇᴇ

我想我回答了“您认为需要对此进行测试以及为什么吗?”的问题。
winkbrace

是的,我认为@winkbrace和我对此有相同的想法。但是我也相信这是关于您应该进行单元测试而不是单元测试的讨论。我认为人们会测试太多和“错误”的东西。在我的示例中,测试控制器的价值很小,因为它太薄了,希望围绕服务进行测试。这里的所有答案都是有意义的,并且有优点,但实际上不可能将其中一个标记为正确答案。

可以使用自动集成测试对控制器逻辑进行测试,这些测试与单个组件的单元测试是分开的,也可以是独立的。
KevBurnsJr

-1:控制器的单元测试可能毫无意义。控制器是关于转换的,但是有时转换本身很复杂,开发人员可能希望涵盖它。我还认为,单元测试1)最终是关于验证实现的,而不一定是在验证高层行为的,而2)应该是很快的。两种质量都使单元测试在实施期间更加有用。换句话说,他们是最后一个开发者的工具,只是偶然的方式来验证产品的质量。
rsenna
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.