Cro Http Test
— 焉知非鱼Cro::HTTP::Test #
原则上可以通过使用 Cro::HTTP::Server托管应用程序, 使用 Cro::HTTP::Client向其发出请求, 并使用标准 Test
库检查结果来编写 Cro HTTP 服务的测试。该库使编写此类测试更容易, 并通过以下方式更快地执行它们:
- 为发出测试请求和检查结果提供更方便的 API
- 跳过网络并将
Cro::TCP
对象从客户端管道传递到服务器管道, 反之亦然
基本示例 #
给定模块 MyService::Routes
, 如下所示:
sub routes() is export {
route {
get -> {
content 'text/plain', 'Nothing to see here';
}
post -> 'add' {
request-body 'application-json' => -> (:$x!, :$y!) {
content 'application/json', { :result($x + $y) };
}
}
}
}
我们可以像这样编写测试:
use Cro::HTTP::Test;
use MyService::Routes;
test-service routes(), {
test get('/'),
status => 200,
content-type => 'text/plain',
body => /nothing/;
test-given '/add', {
test post(json => { :x(37), :y(5) }),
status => 200,
json => { :result(42) };
test post(json => { :x(37) }),
status => 400;
test get(json => { :x(37) }),
status => 405;
}
}
done-testing;
设置要测试的服务 #
test-service
函数有两个候选者。
test-service
(Cro::Transform, &tests, :$fake-auth, :$http)
候选者针对提供的 HTTP 应用程序运行测试, 该应用程序可以是任何使用 Cro::HTTP::Request 的 Cro::Transform
并生成 Cro::HTTP::Response。使用 Cro::HTTP::Router 编写的应用程序执行此操作。也可以使用 Cro.compose
将(可能模拟的)中间件放在适当的位置。可选的 :$fake-auth
参数, 如果传递, 将添加一个中间件, 将请求的 auth
设置为指定的对象。这对于模拟用户或会话以及测试授权非常有用。 http 参数指定运行测试的 HTTP 版本。由于我们在测试中控制客户端和服务器端, 因此不允许设置 :http<1.1 2>
。默认值为 :http<2>
。
test-service($uri, &tests)
候选者针对指定的基 URI 运行测试, 通过 Cro::HTTP::Client 连接到它。这使得可以使用 Cro::HTTP::Test 为使用除 Cro 之外的其他东西构建的服务编写测试。
所有其他命名参数都作为 Cro::HTTP::Client 构造函数参数传递。
写测试 #
test
函数用于传递给 test-service
的块内部。它期望传递一个表示测试请求的位置参数,并命名参数,指示响应的预期属性。
通过调用 get
,put
,post
,delete
,head
或 patch
之一来指定请求。还有其他 HTTP 的 request($method, ...)
(事实上,get
只会调用 request('GET', ...)
)。这些函数接受提供相对 URI 的可选位置参数,如果提供该 URI 将附加到当前有效基 URI。 :$json
命名参数被特殊处理,扩展为 {content-type =>'application/json', body => $json}
。所有其他命名参数将传递给 Cro::HTTP::Client 的 request 方法,从而使所有 HTTP 客户端的功能都可用。
test
函数的命名参数构成检查。它们主要遵循 Cro::HTTP::Response 对象上的方法名称。可用的检查如下。
status #
Smartmatches 响应检查的响应的 status
属性。虽然整数(例如 status => 200
)将是最常见的,但也可能是诸如 status => * <400
之类的事情(例如,不是错误)。
content-type #
检查内容类型是否相同。如果传递了一个字符串,它会将其解析为媒体类型,并检查类型和子类型是否与响应的类型匹配。如果字符串中有任何额外参数(例如字符集),则还将在接收的媒体类型中检查这些参数。如果接收的媒体类型具有未提及的额外参数,则将忽略这些参数。因此,检查content-type =>‘text / plain’匹配text / plain;响应中的charset = utf8。
对于更细粒度的控制,传递一个块,它将传递一个Cro :: MediaType的实例,并期望返回一些测试通过的truthy。
header 或 headers #
将哈希映射头名称转换为头值,或者执行相同的Pair列表。如果标题存在且标题的值与值相匹配,则测试通过。仅在关注标题存在时使用*,但不希望检查其值。响应中的所有其他标头都将被忽略(即,额外的标头被认为是正常的)。
headers => {
Strict-Transport-Security => *,
Cache-Control => /public/
}
为了进一步控制,传递一个块,它将接收一个Pair列表,每个块代表一个头。它的返回值应该是测试通过的真相。
body-text #
获得响应的正文 - 并将其与提供的值进行智能匹配。字符串,正则表达式或代码对象都可能有用。
body-text => /:i success/
如果测试的内容类型且测试失败,则将跳过正文测试。
body-blob #
获得响应的body-blob并将其与提供的值进行智能匹配
body-blob => *.bytes > 128
如果测试的内容类型且测试失败,则将跳过正文测试。
body #
获得响应的主体并将其与提供的值进行智能匹配。请注意,body属性根据响应的内容类型决定要生成的内容,从而选择适当的主体解析器。因此,建议将其与内容类型一起使用(将始终在正文之前进行测试,如果失败则跳过正文测试)。
json #
对于JSON响应的常见情况,这是一个方便的捷径。它实现了content-type => {。type eq’application’&& .subtype-name eq’json’|| .suffix eq’json’}(也就是说,它接受application / json或类似application / vnd.foobar + json的东西)。
如果传递了代码值,那么将使用反序列化的JSON主体调用代码,并且应该返回一个truthy值以供测试通过。否则,将使用is-deep测试例程来检查收到的JSON的结构是否符合预期。
Many tests with one URI, set of headers, etc. #
重复测试的相同细节可能会很繁琐。例如,通常希望针对相同的URI编写许多测试,每次都将其传递给不同的主体或使用不同的请求方法。测试给定的功能有多种形式。它可以与URI和块一起使用:
test-given '/add', {
test post(json => { :x(37), :y(5) }),
status => 200,
json => { :result(42) };
test post(json => { :x(37) }),
status => 400;
}
在这种情况下,测试将全部针对附加到当前有效URI的URI执行,该URI在测试服务块中是被测试服务的基URI。如果各个测试用例也具有URI,则也会附加它。可以嵌套测试给定的块,并且每个块都附加其URI段,从而建立新的当前有效URI。
也可以将命名参数传递给test-given,这些参数将用作请求参数,传递给Cro :: HTTP :: Client。请注意,为get或request指定的任何命名参数都将覆盖在给定测试中指定的参数。
test-given '/add', header => { X-Precision => '15' } {
...
}
第二种形式不需要相对URI,而只需要选项:
test-given header => { X-Precision => '15' } {
...
}