搜索
首页后端开发php教程编写高质量的测试

Writing high quality tests

不幸的是,测试在许多组织中仍然没有得到应有的关注。有时,如果开发人员没有编写任何测试,他们会感到内疚,同时测试代码往往没有得到适当的审查。相反,评论中经常检查的唯一事情是是否有任何测试,这是一种耻辱,因为仅仅进行测试还不够好。实际上,它们至少应该与项目中的所有其他代码具有相同的质量,即使不是更高的质量。否则,测试确实可能会阻碍您,因为测试失败的次数太多,难以理解,或者运行时间太长。我已经在关于使用内存中实现而不是存储库模拟的博客文章中讨论了其中的一些要点。现在我想讨论一些其他的、更一般的、我在编写测试时要注意的事情。

极简主义是关键

Stack Overflow 要求您为问题添加最少的、可重现的示例,在我看来,这对于出于完全相同的原因编写测试也是非常好的建议。尤其是在编写测​​试几个月后阅读测试时,如果发生的事情较少,就更容易完全理解正在发生的事情。因此只编写测试绝对必要的代码,并抵制仅仅因为这样做很容易就添加更多内容的诱惑。但测试代码当然仍然必须完整,即测试应包含尽可能多的行,但尽可能少。

追求 100% 的代码覆盖率

这可能是一个不受欢迎的观点,但我认为以 100% 代码覆盖率为目标是完全有意义的,尽管许多人似乎认为这是一种不好的做法。

有时团队会选择较低的值,例如代码覆盖率达到 90%。然而,这对我来说没有多大意义。首先,所有这些数字都有些随意,并且很难使用数据进行备份。此外,在编写新代码时,并非所有代码都需要经过测试才能通过该阈值。如果有人设法提高了覆盖率,那么下一个人可能根本不编写任何测试,同时仍然保持高于 90% 的代码覆盖率,这会导致错误的自信感。

我经常听到的借口之一是为 getter 和 setter 等简单函数编写测试没有意义。也许令人惊讶的是,我完全同意这一点。但这里有一个问题:如果没有一个测试真正使用这些 getter 和 setter,那么可能就没有必要使用它们。因此,与其抱怨实现 100% 测试覆盖率有多么困难,最好不要首先编写不需要的代码。这也避免了每行代码带来的维护负担。

但是,有一个小问题:有时代码会执行奇怪的操作,这可能会导致代码覆盖工具将某些行标记为未覆盖,即使它是在测试运行期间执行的。我没有经常遇到这样的情况,但如果没有办法使这项工作正常进行,我会将它们排除在代码覆盖范围之外。例如。 PHPUnit 允许使用他们的 codeCoverageIgnore 注释来做到这一点:

<?php class SomeClass
{
    /**
     * @codeCoverageIgnore
     */
    public function doSomethingNotDetectedAsCovered()
    {

    }
}

这样这个函数就不会被包含在代码覆盖率分析中,这意味着仍然有可能达到 100% 的代码覆盖率,并且我也会不断检查该值。另一种方法是选择低于 100% 的值,但这样会出现上面提到的相同问题:其他代码也可能不会被测试覆盖,并且可能会被遗漏。

话虽如此,100% 的代码覆盖率当然不能保证您的代码没有任何错误。但是,如果您的应用程序代码中确实有未覆盖的行,您甚至不会对测试进行更改以发现该行中的潜在错误。

写出好的断言

编写测试的原因是我们想要断言代码的某种行为。因此断言是测试中非常重要的一部分。

当然,编写断言时最重要的考虑因素是它正确地测试代码的行为。但紧随其后的是代码失败时断言的行为方式。如果断言由于某种原因失败,那么问题对于开发人员来说应该尽可能明显。在此 Symfony 拉取请求中当前正在处理的情况就是这种情况显而易见的情况。 Symfony 附带了一个assertResponseStatusCodeSame 方法,它允许在功能测试中检查响应的状态代码:

<?php declare(strict_types=1);

class LoginControllerTest extends WebTestCase
{
    public function testFormAttributes(): void
    {
        $client = static::createClient();

        $client->request('GET', '/login');
        $this->assertResponseStatusCodeSame(200);

        $this->assertSelectorCount(1, 'input[name="email"][required]');
    }
}

这个测试的问题是它在状态码不是 200 的情况下生成的输出。由于测试通常在开发环境中运行,所以当访问这个 URL 时 Symfony 将返回一个错误页面,并且assertResponseStatusCodeSame 方法将输出断言失败时的完整响应。这个输出非常长,因为它不仅返回 HTML,还返回 CSS 和 JavaScript,而且我的回滚缓冲区实际上太小,无法让我阅读整个消息。

这绝对是我迄今为止遇到的最糟糕的例子,但如果代码中使用了错误的断言,它也会很烦人。让我们看一下上面的assertSelectorCount断言的输出,如果给定的选择器没有恰好产生一个元素,则该断言会失败并显示以下消息:

Failed asserting that the Crawler selector "input[name="email"][required]" was expected to be found 1 time(s) but was found 0 time(s).

它很好地了解了发生的问题。但是,断言也可以用不同的方式编写(不要在家里这样做!):

<?php class SomeClass
{
    /**
     * @codeCoverageIgnore
     */
    public function doSomethingNotDetectedAsCovered()
    {

    }
}

有人可能会说这完全一样,因此使用哪种变体并不重要。这与事实相差甚远,因为如果电子邮件没有单个必填输入字段,则会出现以下消息:

<?php declare(strict_types=1);

class LoginControllerTest extends WebTestCase
{
    public function testFormAttributes(): void
    {
        $client = static::createClient();

        $client->request('GET', '/login');
        $this->assertResponseStatusCodeSame(200);

        $this->assertSelectorCount(1, 'input[name="email"][required]');
    }
}

这根本没有帮助,无论谁致力于解决问题,首先都必须弄清楚问题到底是什么。这表明,始终应该使用合适的断言,并且 PHPUnit 附带了许多适合所有类型用例的断言。有时创建自定义断言甚至是有意义的。

近年来我看到越来越流行的一个相对较新的断言是快照测试。尤其是当开始从事前端项目时,它似乎有很大帮助。我过去经常将它与 React 一起使用。主要要点是您的测试看起来像这样:

Failed asserting that the Crawler selector "input[name="email"][required]" was expected to be found 1 time(s) but was found 0 time(s).

神奇的事情发生在 toMatchSnapshot 方法中。在第一次运行时,它将树变量的内容写入单独的文件中。在后续运行中,它将树值的新值与之前存储在单独文件中的值进行比较。如果某些内容发生更改,它将导致测试失败并显示差异,并可以选择再次更新快照,这意味着您可以立即修复测试。

虽然这听起来确实不错,但它也有一些缺点。首先,快照非常脆弱,因为每当组件的渲染标记发生更改时,测试就会失败。其次,测试的意图是隐藏的,因为它没有解释作者真正想要测试的内容。

但是,我真正喜欢它的是,每当我更改组件时,它都会提醒我使用该组件的所有其他组件,因为所有这些快照在下次运行时都会失败。出于这个原因,我喜欢每个组件至少进行一次快照测试。

结论

总而言之,我认为您可以立即开始做一些事情来提高测试质量:

  • 将测试中的代码保持在绝对需要的最低限度
  • 目标是 100% 的代码覆盖率,如果无法测试,请正确地将代码从代码覆盖率机制中排除
  • 当测试失败时,使用正确的断言以获得更好的错误消息

在我看来,遵循这几条规则已经会产生巨大的影响,并帮助您长时间享受在代码库中工作!

以上是编写高质量的测试的详细内容。更多信息请关注PHP中文网其他相关文章!

声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
在Laravel中使用Flash会话数据在Laravel中使用Flash会话数据Mar 12, 2025 pm 05:08 PM

Laravel使用其直观的闪存方法简化了处理临时会话数据。这非常适合在您的应用程序中显示简短的消息,警报或通知。 默认情况下,数据仅针对后续请求: $请求 -

php中的卷曲:如何在REST API中使用PHP卷曲扩展php中的卷曲:如何在REST API中使用PHP卷曲扩展Mar 14, 2025 am 11:42 AM

PHP客户端URL(curl)扩展是开发人员的强大工具,可以与远程服务器和REST API无缝交互。通过利用Libcurl(备受尊敬的多协议文件传输库),PHP curl促进了有效的执行

简化的HTTP响应在Laravel测试中模拟了简化的HTTP响应在Laravel测试中模拟了Mar 12, 2025 pm 05:09 PM

Laravel 提供简洁的 HTTP 响应模拟语法,简化了 HTTP 交互测试。这种方法显着减少了代码冗余,同时使您的测试模拟更直观。 基本实现提供了多种响应类型快捷方式: use Illuminate\Support\Facades\Http; Http::fake([ 'google.com' => 'Hello World', 'github.com' => ['foo' => 'bar'], 'forge.laravel.com' =>

在Codecanyon上的12个最佳PHP聊天脚本在Codecanyon上的12个最佳PHP聊天脚本Mar 13, 2025 pm 12:08 PM

您是否想为客户最紧迫的问题提供实时的即时解决方案? 实时聊天使您可以与客户进行实时对话,并立即解决他们的问题。它允许您为您的自定义提供更快的服务

解释PHP中晚期静态结合的概念。解释PHP中晚期静态结合的概念。Mar 21, 2025 pm 01:33 PM

文章讨论了PHP 5.3中引入的PHP中的晚期静态结合(LSB),从而允许静态方法的运行时分辨率调用以获得更灵活的继承。 LSB的实用应用和潜在的触摸

PHP记录:PHP日志分析的最佳实践PHP记录:PHP日志分析的最佳实践Mar 10, 2025 pm 02:32 PM

PHP日志记录对于监视和调试Web应用程序以及捕获关键事件,错误和运行时行为至关重要。它为系统性能提供了宝贵的见解,有助于识别问题并支持更快的故障排除

如何注册和使用Laravel服务提供商如何注册和使用Laravel服务提供商Mar 07, 2025 am 01:18 AM

Laravel的服务容器和服务提供商是其架构的基础。 本文探讨了服务容器,详细信息服务提供商创建,注册,并通过示例演示了实际用法。 我们将从OVE开始

自定义/扩展框架:如何添加自定义功能。自定义/扩展框架:如何添加自定义功能。Mar 28, 2025 pm 05:12 PM

本文讨论了将自定义功能添加到框架上,专注于理解体系结构,识别扩展点以及集成和调试的最佳实践。

See all articles

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

AI Hentai Generator

AI Hentai Generator

免费生成ai无尽的。

热门文章

R.E.P.O.能量晶体解释及其做什么(黄色晶体)
2 周前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳图形设置
2 周前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您听不到任何人,如何修复音频
2 周前By尊渡假赌尊渡假赌尊渡假赌

热工具

ZendStudio 13.5.1 Mac

ZendStudio 13.5.1 Mac

功能强大的PHP集成开发环境

mPDF

mPDF

mPDF是一个PHP库,可以从UTF-8编码的HTML生成PDF文件。原作者Ian Back编写mPDF以从他的网站上“即时”输出PDF文件,并处理不同的语言。与原始脚本如HTML2FPDF相比,它的速度较慢,并且在使用Unicode字体时生成的文件较大,但支持CSS样式等,并进行了大量增强。支持几乎所有语言,包括RTL(阿拉伯语和希伯来语)和CJK(中日韩)。支持嵌套的块级元素(如P、DIV),

SecLists

SecLists

SecLists是最终安全测试人员的伙伴。它是一个包含各种类型列表的集合,这些列表在安全评估过程中经常使用,都在一个地方。SecLists通过方便地提供安全测试人员可能需要的所有列表,帮助提高安全测试的效率和生产力。列表类型包括用户名、密码、URL、模糊测试有效载荷、敏感数据模式、Web shell等等。测试人员只需将此存储库拉到新的测试机上,他就可以访问到所需的每种类型的列表。

WebStorm Mac版

WebStorm Mac版

好用的JavaScript开发工具

DVWA

DVWA

Damn Vulnerable Web App (DVWA) 是一个PHP/MySQL的Web应用程序,非常容易受到攻击。它的主要目标是成为安全专业人员在合法环境中测试自己的技能和工具的辅助工具,帮助Web开发人员更好地理解保护Web应用程序的过程,并帮助教师/学生在课堂环境中教授/学习Web应用程序安全。DVWA的目标是通过简单直接的界面练习一些最常见的Web漏洞,难度各不相同。请注意,该软件中