Wait the light to fall

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::RequestCro::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 的块内部。它期望传递一个表示测试请求的位置参数,并命名参数,指示响应的预期属性。

通过调用 getputpostdeleteheadpatch 之一来指定请求。还有其他 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' } {
    ...
}