压力测试

压力测试是一种测试类型,它在现实或极端条件下检查应用程序的稳定性和可靠性——具体取决于您设置的场景。例如,您可以使用压力测试来验证您的应用程序是否能够处理大量请求或是否能够处理大量数据。

在 Pest 中,您可以将压力测试的功能与断言 API 结合使用,确保随着时间的推移不会出现稳定性和可靠性回归。这对于在发布新版本或部署新版本后验证应用程序是否稳定和可靠非常有用。

在幕后,此项目利用了 k6,这是一个功能强大的开源负载测试工具,用于评估 API、微服务和网站的性能。k6 采用 AGPL-3.0 许可证 许可,并且在第一次使用插件时会下载 k6 二进制文件。

要开始使用 Pest 的压力测试插件(通常称为 Stressless),您需要通过 Composer 要求 stressless 插件。

1composer require pestphp/pest-plugin-stressless --dev

要求插件后,您可以通过两种不同的方式开始使用它

  • 使用 stress 命令:当您想快速对 URL 进行压力测试,而无需对结果设置断言时,此方法很有用。
  • 使用 stress() 函数:当您想对 URL 进行压力测试并对结果设置断言时,此方法很有用。

测试外部域名或本地 IP 地址?当从外部网络对域名进行负载测试时,您可以真实地了解应用程序在典型用户负载下的性能。这包括网络延迟和现实世界互联网流量等因素。但是,当在网络内测试本地 IP 地址时,重点在于了解在受控环境中内部基础设施的性能,而无需外部变量,例如互联网或 DNS 解析时间。它对于识别您自己网络或服务器中的潜在瓶颈以及内部应用程序或服务器的性能调整特别有用。这包括更有效地配置 PHP FPM 等任务。

Stress 命令

stress 命令在您想快速对 URL 进行压力测试、分析结果,并且无需对结果设置断言时非常有用。它是启动压力测试最快的方法,并且直接在终端上进行。

要开始,您可以使用 stress 命令并提供您希望进行压力测试的 URL

1./vendor/bin/pest stress example.com

默认情况下,压力测试持续时间为 5 秒。但是,您可以使用 --duration 选项自定义此值

1./vendor/bin/pest stress example.com --duration=5

此外,并发请求数将为 1。但是,您也可以使用 --concurrency 选项自定义此值

1./vendor/bin/pest stress example.com --concurrency=5

并发值表示将对给定 URL 发出的并发请求数。例如,如果您将并发设置为 5,则 Pest 将持续对给定 URL 发出 5 个并发请求,直到达到压力测试持续时间。

您可能需要注意您配置的并发请求数。如果您配置了过多的并发请求,则可能会使您的应用程序、服务器过载或达到速率限制/防火墙。

如果要指定压力测试使用的 HTTP 方法,可以使用提供的 deletegetheadoptionspatchputpost 选项之一。使用 optionspatchput 选项,您可以指定一个可选的有效负载参数用于请求中。使用 post 选项,您需要提供有效负载参数。

1./vendor/bin/pest stress example.com/articles
2# or
3./vendor/bin/pest stress example.com/articles --get
4# or
5./vendor/bin/pest stress example.com/articles --head
6# or
7./vendor/bin/pest stress example.com/articles --options
8# or
9./vendor/bin/pest stress example.com/articles --options='{"name": "Nuno"}'
10# or
11./vendor/bin/pest stress example.com/articles/1 --patch
12# or
13./vendor/bin/pest stress example.com/articles/1 --patch='{"name": "Nuno"}'
14# or
15./vendor/bin/pest stress example.com/articles --put
16# or
17./vendor/bin/pest stress example.com/articles --put='{"name": "Nuno"}'
18# or
19./vendor/bin/pest stress example.com/articles --post='{"name": "Nuno"}'
20# or
21./vendor/bin/pest stress example.com/articles/1 --delete

压力测试完成后,Pest 将显示压力测试结果的摘要。

Stress 函数

一旦您开始了解压力测试的工作原理,您可能希望开始对压力测试结果设置断言。例如,您可能希望验证平均响应时间始终小于 100 毫秒,这就是 stress() 函数的用武之地。

要开始,只需创建一个常规测试并使用 stress() 函数对给定 URL 进行压力测试

1<?php
2 
3use function Pest\Stressless\stress;
4 
5it('has a fast response time', function () {
6 $result = stress('example.com');
7 
8 expect($result->requests()->duration()->med())->toBeLessThan(100); // < 100.00ms
9});

默认情况下,压力测试持续时间为 10 秒。但是,您可以使用 for()->seconds() 方法自定义此值

1$result = stress('example.com')->for(5)->seconds();

此外,并发请求数将为 1。但是,您也可以使用 concurrently 方法自定义此值

1$result = stress('example.com')->concurrently(requests: 2)->for(5)->seconds();

在任何时候,您都可以 dd 压力测试结果以查看其详细信息(就像使用 stress 命令一样)。

1$result = stress('example.com')->dd();
2 //->dump();
3 //->verbosely();

如果要指定压力测试使用的 HTTP 方法,可以使用提供的 deletegetheadoptionspatchputpost 方法之一。使用 optionspatchput 方法,您可以指定一个可选的有效负载参数用于请求中。使用 post 方法,您需要提供有效负载参数。

1$result = stress('example.com/articles/1')->delete();
2// or
3$result = stress('example.com/articles')->get();
4// or
5$result = stress('example.com/articles')->head();
6// or
7$result = stress('example.com/articles')->options();
8// or
9$result = stress('example.com/articles')->options(["name" => "Nuno"]);
10// or
11$result = stress('example.com/articles/1')->patch();
12// or
13$result = stress('example.com/articles/1')->patch(["name" => "Nuno"]);
14// or
15$result = stress('example.com/articles')->put();
16// or
17$result = stress('example.com/articles')->put(["name" => "Nuno"]);
18// or
19$result = stress('example.com/articles')->post(["name" => "Nuno"]);

stress() 函数返回压力测试结果,您可以使用它来设置断言。以下是可用方法的列表

请求持续时间

返回以毫秒为单位的总请求持续时间。

1$result->requests()->duration()->med();
2 // ->min();
3 // ->max();
4 // ->p90();
5 // ->p95();

请求次数

返回发出的请求数。

1$result->requests()->count();

请求速率

返回每秒发出的请求数。

1$result->requests()->rate();

请求失败次数

返回失败的请求数。

1$result->requests()->failed()->count();

请求失败率

返回每秒失败的请求数。

1$result->requests()->failed()->rate();

请求首字节时间持续时间/TTFB

返回以毫秒为单位的请求首字节时间持续时间。

1$result->requests()->ttfb()->duration()->med();
2 // ->min();
3 // ->max();
4 // ->p90();
5 // ->p95();

请求 DNS 查找持续时间

此指标受客户端和 DNS 服务器之间的网络延迟影响。

返回以毫秒为单位的请求 DNS 查找持续时间。

1$result->requests()->dnsLookup()->duration()->med();
2 // ->min();
3 // ->max();
4 // ->p90();
5 // ->p95();

请求 TLS 握手持续时间

此指标受客户端和服务器之间的网络延迟影响。

返回以毫秒为单位的请求 TLS 握手持续时间。

1$result->requests()->tlsHandshaking()->duration()->med();
2 // ->min();
3 // ->max();
4 // ->p90();
5 // ->p95();

请求下载持续时间

此指标受客户端和服务器之间的网络延迟影响。

返回以毫秒为单位的请求下载持续时间。

1$result->requests()->download()->duration()->med();
2 // ->min();
3 // ->max();
4 // ->p90();
5 // ->p95();

请求下载数据量

返回以字节为单位的请求下载数据量。

1$result->requests()->download()->data()->count();

请求下载数据速率

返回以每秒字节为单位的请求下载数据速率。

1$result->requests()->download()->data()->rate();

请求上传持续时间

此指标受客户端和服务器之间的网络延迟影响。

返回以毫秒为单位的请求上传持续时间。

1$result->requests()->upload()->duration()->med();
2 // ->min();
3 // ->max();
4 // ->p90();
5 // ->p95();

请求上传数据量

返回以字节为单位的请求上传数据量。

1$result->requests()->upload()->data()->count();

请求上传数据速率

返回以每秒字节为单位的请求上传数据速率。

1$result->requests()->upload()->data()->rate();

测试运行并发

返回压力测试期间发出的并发请求数,即您使用 --concurrency 选项或 concurrently 方法设置的值。

1$result->testRun()->concurrency();

测试运行持续时间

返回压力测试的持续时间,即您使用 --duration 选项或 for()->seconds() 方法设置的值。

1$result->testRun()->duration();

在这里,我们已经了解了如何使用 Pest 的压力测试插件(也称为 stressless)对给定 URL 进行压力测试并对结果设置断言。接下来,让我们探索如何测试测试代码的覆盖率:测试覆盖率