【译】ASP.NET Core测试工具与技巧

1,363 阅读10分钟

原文链接

讨论web开发的多种测试(单元测试,集成测试等),以及ASP.NET Core中对应的工具。

不知道有没有人有这样的经历,因为你web应用出现了问题,在午夜的睡梦中被叫醒。避免出现这种问题的解决方案就是彻底地测试你的应用程序。当然,测试也是一种负担,所以常常会跳过深入的测试,假装所有的代码都测试通过了。找出测试的关键点,合理使用ASP.NET Core测试工具是需要经验的。

过度的测试会对我们的项目产生负面的影响,这种影响取决于被测试的代码的复杂度与对整个项目的影响程度。有一个比较复杂的问题是,我们有很多种方式来测试代码。你一定听说过测试三角吧,我们也称它为测试金字塔。

测试三角

这个三角形展示了对于每种测试你应该进行的次数。你的大部分测试应该是单元测试:它测试一个类中的单个方法。测试三角越往上,测试的次数越少,测试的规模越大,单个测试的成本递增。

在这篇文章中,我们会看一看测试工具在金字塔的每一层怎么帮助我们。一些工具是针对.NET的,还有一些几乎对所有的开发平台都适用,在随后的展开中我们会逐一指出。你会看到,随着金字塔的上升,测试技术变得更广泛,能对更多的web开发技术适用。

测试三角对于ASP.NET Core的测试策略是一个很好的指导。

单元测试

单元测试是你写的最小的测试。理论上,它运行一个方法,写起来相当琐碎。事实上,许多人这样建议,如果你发现单元测试很难写,那就说明你测试的代码执行的任务过多(违背了单一职责原则),需要分离。我也将单元测试当作一个指标,将方法分到多个方法甚至多个类里。这就是在测试驱动开发中你创建的那些测试。

单元测试工具并不是.NET中的新生事物。向.NET Core迁移的时候,就带了许多一流的单元测试工具。单元测试工具分为许多种类:测试框架,测试运行器以及断言库。框架就是一系列的特性,装饰在你的代码上,让它们能被找到并运行。

通常,测试框架也包含一个运行器,能够在整个应用不启动的情况下运行测试。最后,断言库用来检查测试中的条件——大多数人坚持使用框架提供的断言。所有这些工具都能够在.NET项目中运行,不限于ASP.NET。

测试框架

我个人最喜欢的测试框架是xUnit,这是.NET Foundation开源项目的一部分。这保证了它的生命力以及在社区的知名度。xUnit一直致力于变得更快。它所用的术语与你之前熟知的那些可能有些许不同,使用Fact,Theory取代了Test与ParameterizedTest。在.NET Core孵化期间,xUint是唯一紧跟版本的单元测试框架。

最近,微软开源了他们的MSTest框架的第二个版本。MSTest已经有些年头了,亟需更新。不过,新版本还不错并且非常快。两年以前,我完全不会考虑MSTest,但是现在它已经相当有竞争力了。

我的同事Erik在他的博客里对.NET的单元测试框架做了深入的比较。

测试执行器

测试执行器执行测试,并展示一个易于理解的结果。如果你在使用Visual Studio,那么就没必要再找其他的执行器了,因为内置的执行器就很好用。

在过去的几个发行版中,这个工具受到了团队的大力支持。测试运行与发现速度都非常快。除了标准的执行器,现在还有实时单元测试。该工具在你写代码的同时执行测试。

.NET Core的命令行工具也很出色。官方文档有个运行命令行测试的指南,这种方式也可以在构建服务器上运行。xUnit能检测到它正运行在持续集成(CI)环境中,并将输出格式转为CI服务器能够解析的格式。

断言库

几乎每个人都使用框架自带的断言。但是,还有更好的选择,ShouldlyFluent Assertions提供了一个更加BDD风格的断言。这意味着什么呢?以前都是这么写:

Assert.That(location.X, Is.EqualTo(1337));

现在,可以这样写:

location.X.ShouldBe(1337); 

由这些库所产生的错误信息也更易读,节省找问题的时间。

其他语言的单元测试

由于这些工具运行于.NET框架,以此它们也能用在F#上,就像F#代码可以用来测试C#代码一样。F#也有好用的测试工具,如果你乐于尝试,可以深入了解一下,F#与单元测试

集成测试

集成测试比单元测试更大,通常跨模块。你可能会问什么是模块?这是个好问题。

一个模块可能就是一个类,因此一个简单的集成测试可能就是在两个类之间调用。一个模块也可能跨应用程序边界,可能是数据库与代码的集成。

单元测试的“口号”是快(在开发沙盒中快速运行不用打断你的工作流),集成测试的“口号”是并行。每个测试本身都要花费很长时间,需要使用多核的机器解决并行问题。

基于请求的测试工具

通常,web项目的集成测试需要提交一个请求到web服务器并查看返回值。过去,编写这种集成测试非常棘手。对于ASP.NET Core测试,TestServer的介入使情况得到了改善。该服务器允许你向一个内存中的HTTP服务器提交请求,这样更快,更易查看返回结果。可以在官方文档中更深入了解ASP.NET Core的集成测试。

有一个好用的工具可以检测终端返回的HTML,AngleSharp。AngleSharp提供了一个API来解析并检测DOM。

数据库集成测试

过去,我写过很多令人印象深刻的与数据库有关的可以运行集成测试的代码。虽然在当时它们都是相当时髦的代码,测试的速度却很受限制。幸运的是,现在我们有了Entity Framework Core。就像TestServer,EF Core提供了一个内存中的数据库实现,这个数据库可以快速测试基于LINQ的查询。但是使用SQL写的查询不能以这种方式测试,对于这种情况,我建议读读Paquette的文章

验收测试

像集成测试一样,验收测试也会跨模块,但是它们是从用户的视角出发的。这些测试的任务往往是描述系统的行为而不是功能,你的测试模拟的是用户的体验。

在.NET中,有两个主要的工具:SpecFlowNSpec。这两个工具的主要不同是描述测试的方式。SpecFlow使用Gherkin语言,这个语言来自于Cucumber工具语言。NSpec使用它自己的语言描述测试。两种工具都很好,但是我发现SpecFlow可能更有用,你的实际使用可能跟我有所不同。

UI测试

最高级别的自动化测试是UI测试。这些测试驱使web浏览器以自动化的方式执行鼠标点击,输入文本,点击链接。在.NET中,我更偏好使用Canopy。就我的经验来说,UI测试非常脆弱且不一致。我很愿意相信是我的工作不利导致这种情况,但是,在我请教了其他人以后发现并不是如此。很多问题源自于浏览器不是设计来处理自动化的,而且缺少针对程序的hook。通常,测试ASP.NET web应用时要添加许多Sleep,以希望UI有时间进行更新。最近,我听说了一个新的工具叫做Cypress,但是我还没有用过。如果你用过,请在评论里告诉我。

UI测试工具适用于多种web应用,不限于ASP.NET。

手动测试

手动测试通常被认为是件苦差事。许多公司都尽量避免手动测试,喜欢更便宜的自动测试。自动测试没法告诉你用户体验。让一些实际的用户使用你的网站很重要。手动测试能够发现与单元测试,集成测试或其他测试所不同的问题。

性能测试

ASP.NET Core真的,真的很快,在web框架中是数一数二的。然而,它的性能很容易被糟糕的代码破坏。有两种测试可以使用:低级测试与负载测试。

低级测试

低级性能测试可以回答这种问题,“序列化该数据流的最快方式是什么?”,“高负载会造成过多内存分配吗?”。这些问题很少被问及,大部分应用都是简单地从数据库取数据并显示,它们不关心这些。但是随着你的代码处理计算密集型或内存密集型的任务,这些变得很重要。最流行的工具是BenchmarkDotNet

这个工具提供了特性与测试运行器,输出像这样:

从上面的例子可以看出,代码在不同的平台上以不同的样本大小做测试。这些测试能够发现问题,并确保随着应用的成熟性能不会倒退。

负载测试

网站开始流行,人们蜂拥而至,这是所有人都希望的。但是在这之前,了解你的应用在负载下的性能能帮助你保证你的睡眠与周末不会被打断。我推荐的工具是Visual Studio Team Services的负载测试工具。使用Auzere ASTS中的数百万台机器能够发起大规模的负载测试,为你的应用带来巨大的负载压力,这是任何桌面工具都提供不了的。收费也相当合理,我强烈推荐。

请求追踪

负载测试与低级测试都能保障你的应用性能。但是,没有人能够预测真正的用户负载长啥样。Retrace是一个非常好用的工具,能够监控你的网站的实时性能,找出慢查询,代码瓶颈和隐藏的错误。

Retrace的姐妹工具,Prefix在显示一个高级的应用性能总览时简直时无价之宝。负载测试只能告诉你你的站点很慢,Prefix能告诉你为什么。而且Prefix还是免费的。

可用性测试

可达性测试使你的应用向更多的人开放。你的用户可能是盲人,活动受限,色盲,你的站点应该对他们可用。这篇文章太短了没法介绍所有这些工具,有兴趣可以查看相关文章

选择困难

在当今世界,选择困难是一个实际的问题,面对这么多的测试工具,很容易产生选择困难。我希望这篇文章至少为你指明了一个方向。如果你正在做ASP.NET Core测试,那是一个巨大的胜利,毕竟聊胜于无嘛。前进吧!测试吧!