digitonic/api-test-suite

Laravel API CRUD 测试框架

3.0.1 2022-07-25 12:55 UTC

README

Latest Version on Packagist Build Status Scrutinizer Code Quality Total Downloads

一套围绕确认您的每个API端点都设置为符合配置标准的测试工具。

安装

您可以通过composer安装此包

$ composer require digitonic/api-test-suite

安装配置和模板

$ php artisan digitonic:api-test-suite:install

使用方法

通用结构

您想要扩展以启用测试框架功能的主要类是CRUDTestCase。这是通过runBaseApiTestSuite()方法自动断言测试套件的主要入口点。此类还提供了一个默认的setUp()方法,用于创建用户。CRUDTestCase类扩展了您的应用中的基础Laravel TestCase,因此它还会考虑您在那里所做的所有更改,例如迁移运行、setUp或tearDown方法;

配置文件

在您运行安装命令时,此文件在config/digitonic中生成: php artisan digitonic:api-test-suite:installphp artisan d:a:i(简称)。它包含以下选项

api_user_class

这是用于您的基用户类的类。例如:App\Models\User::class

required_response_headers

一个包含头-头值对的数组,将返回所有API路由。如果任何值不存在,您可以设置头值的值为null。这可以在测试类的AssertsOuput trait的checkRequiredResponseHeaders方法级别通过重写来覆盖。

default_headers

将传递给所有API调用的默认头。键应为大写字母,并以HTTP开头,遵循guzzle样式。例如:['HTTP_ACCEPT' => 'application/json']

entities_per_page

在此处指示索引请求中响应应具有的最大实体数。这用于分页测试。

identifier_field

一个闭包,返回一个字符串,确定ID字段的名称。您在此处可以访问与测试相同的上下文。例如:对于所有实体的uuid使用function () {return 'uuid';}

identifier_faker

一个闭包来伪造一个标识符。主要用于测试NOT_FOUND状态码。例如:用于生成payload中明天的日期的function () {return \App\Concerns\HasUuid::generateUuid();}

templates

一个数组,包含一个base_path键,该键具有一个字符串值,指示分页和错误响应模板的路径。例如:['base_path' => base_path('tests/templates/')

creation_rules

可能是最有用的配置选项。它允许为您的有效负载创建临时的创建规则。它应该是一个数组,其中包含测试中使用的创建规则名称作为键,闭包返回适当的值作为值。例如:['tomorrow' => function () {return Carbon::parse('+1day')->format('Y-m-d H:i:s');}] 允许您在有效负载中生成明天的日期。我们将在看到creationRules()方法时再回到它。

setUp()方法

此方法生成

  • 一个在您的测试中任何地方都可以使用的identifierGenerator字段,基于您的identifier_faker配置(见上方)。
  • 一个新的默认为空Laravel Collection的entities字段。
  • 一个表示API中资源合法用户的user字段。这需要你在factories文件夹中为api_user_class创建一个crud工厂状态。这应该设置用户默认字段以及与团队/组织的关联。
  • 一个使用相同工厂创建的otherUser字段,它代表一个不应访问所访问资源的用户。确保你的工厂crud状态每次调用时创建不同的团队。

所有这些字段都可以在测试类的任何地方使用。

runBaseApiTestSuite()方法

这个方法就是魔法所在。大多数经典的CRUD端点可以直接使用该方法,但一些更复杂的端点可能需要覆盖它以正确获取测试套件的上下文。如果是这种情况,所有的CRUDTestCase方法仍然可用,以帮助你构建测试。

该方法按以下顺序运行以下断言

  • 未提供授权令牌时的Unauthorized状态码和错误格式。
  • 提供不存在标识符时,资源为Not Found状态码和错误格式。
  • 忘记必填字段时的Unprocessable entity状态码和错误格式。
  • 尝试访问没有权限访问的资源时,返回Forbidden状态码和错误格式。
  • 如果缺少必要头(我们需要设置系统性地设置Accept: application/json,这是API输出完整性的保证,否则你可能会在未经授权的请求上发生Web重定向等),则返回Bad Request状态码和错误格式。这也可以用来强制设置其他HTTP头。如果提供了该头,它将测试该头的值。
  • Created状态码,以及响应数据格式,包括提供的链接和时间戳,如果指定了,还包括id替换值(例如,使用uuid而不是id)。如果资源不应重复,它还会确保仅创建一次(或两次,如果可以重复)。
  • Accepted状态码,以及响应数据格式,包括提供的链接和时间戳(必须更新updated_at),如果指定了,还包括id替换值(例如,使用uuid而不是id)。
  • OK状态码,以及响应数据格式,包括提供的链接和时间戳,如果指定了,还包括id替换值(例如,使用uuid而不是id)对于ListAll和Retrieve端点。在ListAll端点的情况下,如果测试设置为这样做,还会测试每页最大数量和格式。
  • No Content状态码,以及Delete端点的空响应体。

将运行哪个断言由CRUDTestCase类中的DeterminesAssertions Trait决定。该方法基于你通过实现CRUDTestCase抽象方法提供的关于端点的元数据。如果你发现运行了意外的断言,我鼓励你阅读该文件,并在必要时覆盖它们。

测试接口实现

为了帮助你,该包提供了一些你可以用来为创建、检索、更新、列表和删除操作设置默认值的Trait(分别是TestsCreateActionTestsRetrieveActionTestsUpdateActionTestsListAllActionTestsDeleteAction)。这些为以下方法提供了合理的默认值:httpAction()statusCodes()shouldAssertPaginate()requiredHeaders()creationHeaders()requiredFields()cannotBeDuplicated()。如果需要,可以在测试类中覆盖这些值。

资源元数据

resourceClass()

返回当前实体的类名。

createResource()

此方法应返回一个字符串(您创建端点路由的名称,例如 campaigns.api.store),如果您选择使用您的API创建端点来创建测试的资源。在这种情况下,如果破坏了创建端点,则预期其他相关端点测试会失败。否则,您可以为测试设置数据库所需状态并提供一个闭包,返回目标实体,就像您的创建端点所做的那样(作为一个对象,而不是数组或JSON)。

creationRules()

这应该返回一个表单字段的关联数组。每个字段都应该使用来自API测试套件的可用规则,或者是在您的api-test-suite.php配置文件中声明的自定义规则。默认可用的规则可以在此文件中看到。

viewableByOwnerOnly()

如果您正在创建的资源仅由资源所有者可用,则应返回true;否则返回false。

cannotBeDuplicated()

如果资源可以在几个创建端点调用中用相同的有效负载重复,则应返回true;否则返回false。

##请求元数据

httpAction()

应返回以下值之一作为字符串,具体取决于端点允许的方法:get、post、put或delete。

requiredFields()

这应返回您请求的必要字段的非关联数组。对创建端点最有用。例如:['code', 'sender', 'send_at', 'is_live']

requiredHeaders()

这些是要在请求中强制执行存在的头信息。如果您使用辅助特性,则默认为配置文件中的默认头信息。例如:['HTTP_ACCEPT' => 'application/json']

creationHeaders()

如果您选择使用API创建资源(请参阅下面的createResource()方法),则应与requiredHeaders()返回值匹配您的创建端点。例如:['HTTP_ACCEPT' => 'application/json']

响应元数据

statusCodes()

此方法确定端点应返回哪些状态码,即测试成功和错误的不同的场景。因此,理解这一点非常重要 此方法应返回在runBaseApiTestSuite()方法部分中的上述状态码数组。然而,辅助特性的默认值通常不是您想要的。 例如:[Response::HTTP_CREATED,Response::HTTP_UNPROCESSABLE_ENTITY,Response::HTTP_UNAUTHORIZED]

expectedResourceData(array $data)

此方法是一种声明预期值的方式。大多数时候,它将是有效负载,加上或减去一些字段。您可以从$data数组中添加这些字段,如果无法预先知道将返回什么值(例如,对于时间戳)。

expectsTimestamps()

如果API返回created_at和updated_at时间戳,则返回true;否则返回false。

expectedLinks()

返回与您的实体相关的链接数组。 例如:['self' => 'campaigns.api.show']。这尚未用于任何其他类型的链接。

fieldsReplacement()

返回一个数组,键是当前实体字段,这些字段不应公开,因此用对的值替换。 例如,['id' => 'uuid'] 以检查id不存在,而uuid在返回的API数据中存在。

shouldAssertPaginate()

这应返回true,如果端点应该分页,否则返回false。通常对ListAll端点有用。

checkRequiredResponseHeaders()

返回一个列表,其中包含服务器必须包含在端点响应中的头信息和值。如果任何值缺失,您可以设置头信息的值为null。

辅助方法和字段

您当然可以使用runBaseApiTestSuite中使用的任何子例程来编写一个更灵活、定制的端点测试套件。

CRUDTestCase类提供的一些有用方法是以下这些

  • getCurrentIdentifier() 返回根据您的配置文件设置的正在测试的实体的标识符。

  • doAuthenticatedRequest($data, array $params = [], $headers = []) 对您的端点执行配置的请求,允许您传递一个用于负载的 $data 数组,以及自定义 $params(用于构建目标 URL,例如 campaignUuid)和头部(这些将覆盖配置中设置的默认头部。如果未设置或为空,则使用默认值);它还会将测试中的 actingAs 设置为 $this->user。

  • doRequest($data, array $params = [], $headers = []) 与上述相同,但不将 actingAs 设置为 $this->user

  • getResponseData(TestResponse $response) 允许您轻松提取响应中的 data 属性。

  • generateEntities($numberOfEntities, $httpAction, $baseUser, $otherUser) 将为提供的 $baseUser 创建指定数量的 resourceClass() 实体。此外,如果 $httpAction 是 'get' 且 $this->viewableByOwnerOnly() 返回 true,则将使用 $otherUser 创建另一个实体,该实体不属于 $baseUser,以便测试它不能被 $baseUser 看到。

  • generatePayload($user) 返回一个符合由 $this->creationRules() 返回的规则的 $user 负载。

  • generateEntityOverApi(array $payload, $user) 根据提供的负载和用户创建当前实体。这需要 createResource 方法返回一个端点名称。

  • generateUpdateData($payload, $user) 从传递给它的创建负载中生成一个更新负载。

  • identifier() 是当前上下文中的标识符键。在尝试构建自定义测试时,如果您在 api-test-suite 配置中创建 identifier_field 闭包遇到问题,这会非常有用。

  • generateSingleEntity($user, $payload = null) 返回一个当前类型的实体。如果您不传递特定的负载,它将使用上述 generatePayload($user) 创建一个。

分页和错误模板

使用配置文件中的 templates 字段来指示您的自动化测试套件的模板位置。默认情况下,它们将在 tests/templates 中。在运行安装程序命令时提供了默认值,以帮助您开始。

分页

分页模板当前没有默认值。如果您保持原样,则不会使用它。

错误

错误模板应该命名为您期望的状态码(您应该有以下文件:400.blade.php, 401.blade.php, 403.blade.php, 404.blade.php 和 422.blade.php)。为了方便起见,模板允许使用正则表达式,并且 422 模板传递了两个变量:'fieldName'(在您的 requiredFields() 中正在测试的必需键)和 'formattedFieldName',这是相同字段在 snake_case 中的形式。

测试

composer test

变更日志

有关最近更改的更多信息,请参阅 变更日志

贡献

有关详细信息,请参阅 贡献指南

安全

如果您发现任何与安全相关的问题,请通过电子邮件 steven@digitonic.co.uk 而不是使用问题跟踪器。

鸣谢

许可

MIT 许可证(MIT)。有关更多信息,请参阅 许可文件