Mojolicious-8.12 > Mojolicious::Guides::Testing
Mojolicious-8.12

名前

Mojolicious::Guides::Testing - Web Application Testing Made Easy

Mojolicious::Guides::Testing - Webアプリケーションのテストを簡単に

(訳注: (TBR)がついている段落は「みんなの自動翻訳@TexTra」による 機械翻訳です。)

OVERVIEW

This document is an introduction to testing web applications with Test::Mojo. Test::Mojo can be thought of as a module that provides all of the tools and testing assertions needed to test web applications in a Perl-ish way.

この文書では、Test::Mojoを使用してWebアプリケーションをテストする方法を 紹介します。 Test::Mojoは、Perl風の方法でWebアプリケーションをテストするために必要な すべてのツールとテストアサーションを提供するモジュールと考えることができます。

While Test::Mojo can be used to test any web application, it has shortcuts designed to make testing Mojolicious web applications easy and pain-free.

Test::Mojoはあらゆるウェブアプリケーションのテストに使えますが、 Mojoliciousウェブアプリケーションのテストを簡単かつ苦痛なく行うための ショートカットが用意されています。

Please refer to the Test::Mojo documentation for a complete reference to many of the ideas and syntax introduced in this document.

この文書で紹介されている多くのアイデアと構文の完全な参照については、 Test::Mojoの文書を参照してください。

A test file for a simple web application might look like:

単純なWebアプリケーションのテストファイルは、次のようになります:

  use Mojo::Base -strict;

  use Test::Mojo;
  use Test::More;

  # Start a Mojolicious app named "Celestial"
  my $t = Test::Mojo->new('Celestial');

  # Post a JSON document
  $t->post_ok('/notifications' => json => {event => 'full moon'})
    ->status_is(201)
    ->json_is('/message' => 'notification created');

  # Perform GET requests and look at the responses
  $t->get_ok('/sunrise')
    ->status_is(200)
    ->content_like(qr/ am$/);
  $t->get_ok('/sunset')
    ->status_is(200)
    ->content_like(qr/ pm$/);

  # Post a URL-encoded form
  $t->post_ok('/insurance' => form => {name => 'Jimmy', amount => '€3.000.000'})
    ->status_is(200);

  # Use Test::More's like() to check the response
  like $t->tx->res->dom->at('div#thanks')->text, qr/thank you/, 'thanks';

  done_testing();

In the rest of this document we'll explore these concepts and others related to Test::Mojo.

この文書の残りの部分では、これらの概念とTest::Mojoに関連する その他の概念について説明します。

CONCEPTS

Essentials every Mojolicious developer should know.

すべてのMojolicious開発者が知っておくべき重要なこと。

Test::Mojo at a glance

(Test::Mojo の概要)

The Test::More module bundled with Perl includes several primitive test assertions, such as ok, is, isnt, like, unlike, cmp_ok, etc. An assertion "passes" if its expression returns a true value. The assertion method prints "ok" or "not ok" if an assertion passes or fails (respectively).

Perlに同梱されているTest::Moreモジュールには、okisisntlikeunlikecmp_okなど、いくつかの基本的な テストアサーションが含まれています。 アサーションは、その式が真の値を返した場合に「合格」します。 アサーションメソッドは、アサーションが合格した場合は「ok」、 不合格の場合は「not ok」を出力します。

Test::Mojo supplies additional test assertions organized around the web application request/response transaction (transport, response headers, response bodies, etc.), and WebSocket communications.

Test::Mojoは、Webアプリケーションの要求/応答トランザクション (トランスポート、応答ヘッダー、応答ボディなど)とWebSocket通信を中心に 構成された追加のテストアサーションを提供します。

One interesting thing of note: the return value of Test::Mojo object assertions is always the test object itself, allowing us to "chain" test assertion methods. So rather than grouping related test statements like this:

注目すべき興味深い点は、Test::Mojoオブジェクトアサーションの戻り値は 常にテストオブジェクト自体であり、テストアサーションメソッドを 「チェーン」できることです; したがって、次のように関連するテストステートメントを グループ化するのではなく:

  $t->get_ok('/frogs');
  $t->status_is(200);
  $t->content_like(qr/bullfrog/);
  $t->content_like(qr/hypnotoad/);

Method chaining allows us to connect test assertions that belong together:

メソッドチェーンを使用すると、互いに属するテストアサーションを接続できます:

  $t->get_ok('/frogs')
    ->status_is(200)
    ->content_like(qr/bullfrog/)
    ->content_like(qr/hypnotoad/);

This makes for a much more concise and coherent testing experience: concise because we are not repeating the invocant for each test, and coherent because assertions that belong to the same request are syntactically bound in the same method chain.

これにより、テストエクスペリエンスの簡潔性凝集性が大幅に向上します。 テストごとに呼び出しを繰り返さないため簡潔であり、 同じリクエストに属するアサーションが同じメソッドチェーン内で 構文的にバインドされるため凝集性があります。

Occasionally it makes sense to break up a test to perform more complex assertions on a response. Test::Mojo exposes the entire transaction object so you can get all the data you need from a response:

場合によっては、テストを分割して、応答に対してより複雑なアサーションを 実行することが理にかなっています。 Test::Mojoはトランザクションオブジェクト全体を公開するため、 応答から必要なすべてのデータを取得できます:

  $t->put_ok('/bees' => json => {type => 'worker', name => 'Karl'})
    ->status_is(202)
    ->json_has('/id');

  # Pull out the id from the response
  my $newbee = $t->tx->res->json('/id');

  # Make a new request with data from the previous response
  $t->get_ok("/bees/$newbee")
    ->status_is(200)
    ->json_is('/name' => 'Karl');

The Test::Mojo object is stateful. As long as we haven't started a new transaction by invoking one of the *_ok methods, the request and response objects from the previous transaction are available in the Test::Mojo object:

Test::Mojoオブジェクトはステートフルです。 *_okメソッドの1つを呼び出して新しいトランザクションを開始していない限り、 前のトランザクションの要求オブジェクトと応答オブジェクトは Test::Mojoオブジェクトで使用できます:

  # First transaction
  $t->get_ok('/frogs?q=bullfrog' => {'Content-Type' => 'application/json'})
    ->status_is(200)
    ->json_like('/0/species' => qr/catesbeianus/i);

  # Still first transaction
  $t->content_type_is('application/json');

  # Second transaction
  $t->get_ok('/frogs?q=banjo' => {'Content-Type' => 'text/html'})
    ->status_is(200)
    ->content_like(qr/interioris/i);

  # Still second transaction
  $t->content_type_is('text/html');

This statefulness also enables Test::Mojo to handle sessions, follow redirects, and inspect past responses during a redirect.

このステートフルさにより、Test::Mojoはセッションを処理し、 リダイレクトに従い、リダイレクト中に過去の応答を検査することもできます。

The Test::Mojo object

(Test::Mojo オブジェクト)

The Test::Mojo object manages the Mojolicious application lifecycle (if a Mojolicious application class is supplied) as well as exposes the built-in Mojo::UserAgent object. To create a bare Test::Mojo object:

Test::Mojoオブジェクトは、Mojoliciousアプリケーションのライフサイクルを 管理し(Mojoliciousアプリケーションクラスが提供されている場合)、 組み込みのMojo::UserAgentオブジェクトを公開します。 生のTest::Mojoオブジェクトを作成するには:

  my $t = Test::Mojo->new;

This object initializes a Mojo::UserAgent object and provides a variety of test assertion methods for accessing a web application. For example, with this object, we could test any running web application:

このオブジェクトは、Mojo::UserAgentオブジェクトを初期化し、 Webアプリケーションにアクセスするための 様々なテストアサーションメソッドを提供します。 たとえば、このオブジェクトを使用して、 実行中のWebアプリケーションをテストできます:

  $t->get_ok('https://www.google.com/')
    ->status_is(200)
    ->content_like(qr/search/i);

You can access the user agent directly if you want to make web requests without triggering test assertions:

テストアサーションをトリガせずにWeb要求を行う場合は、 ユーザエージェントに直接アクセスできます。

  my $tx = $t->ua->post(
    'https://duckduckgo.com/html' => form => {q => 'hypnotoad'});
  $tx->result->dom->find('a.result__a')->each(sub { say $_->text });

See Mojo::UserAgent for the complete API and return values.

完全なAPIと戻り値については、Mojo::UserAgentを参照してください。

Mojoliciousアプリケーションのテスト

If you pass the name of a Mojolicious application class (e.g., 'MyApp') to the Test::Mojo constructor, Test::Mojo will instantiate the class and start it, and cause it to listen on a random (unused) port number. Testing a Mojolicious application using Test::Mojo will never conflict with running applications, including the application you're testing.

Mojoliciousアプリケーションクラスの名前(例:'MyApp')をTest::Mojoコンストラクタに渡すと、Test::Mojoはクラスをインスタンス化して起動し、ランダムな(未使用の)ポート番号をリッスンするようにします。 Test::Mojoを使用してMojoliciousアプリケーションをテストしても、テストしているアプリケーションを含めて、実行中のアプリケーションと競合することはありません。 (TBR)

The Mojo::UserAgent object in Test::Mojo will know where the application is running and make requests to it. Once the tests have completed, the Mojolicious application will be torn down.

Test::Mojo内のMojo::UserAgentオブジェクトは、アプリケーションが実行されている場所を認識し、それに対して要求を行います。 テストが完了すると、Mojoliciousアプリケーションは破棄されます。 (TBR)

  # Listens on localhost:32114 (some unused TCP port)
  my $t = Test::Mojo->new('Frogs');

This object initializes a Mojo::UserAgent object, loads the Mojolicious application Frogs, binds and listens on a free TCP port (e.g., 32114), and starts the application event loop. When the Test::Mojo object ($t) goes out of scope, the application is stopped.

このオブジェクトは、Mojo::UserAgentオブジェクトを初期化し、MojoliciousアプリケーションFrogsをロードし、空きTCPポート(例:32114)にバインドしてリッスンし、アプリケーションイベントループを開始します。 Test::Mojoオブジェクト($t)が範囲外になると、アプリケーションは停止します。 (TBR)

Relative URLs in the test object method assertions (get_ok, post_ok, etc.) will be sent to the Mojolicious application started by Test::Mojo:

テストオブジェクトメソッドアサーション内の相対URL(get_okpost_okなど)は、Test::Mojoによって起動されるMojoliciousアプリケーションに送信されます。 (TBR)

  # Rewritten to "http://localhost:32114/frogs"
  $t->get_ok('/frogs');

Test::Mojo has a lot of handy shortcuts built into it to make testing Mojolicious or Mojolicious::Lite applications enjoyable.

Test::Mojoには、MojoliciousまたはMojolicious::Liteアプリケーションのテストを楽しくするための便利なショートカットがたくさん組み込まれています。 (TBR)

Let's spin up a Mojolicious application using mojo generate app MyApp. The mojo utility will create a working application and a t directory with a working test file:

mojo generate app MyAppを使用してMojoliciousアプリケーションを起動してみましょう。 mojoユーティリティは、動作するアプリケーションと、動作するテストファイルを含むtディレクトリを作成します。 (TBR)

  $ mojo generate app MyApp
  [mkdir] /my_app/script
  [write] /my_app/script/my_app
  [chmod] /my_app/script/my_app 744
  ...
  [mkdir] /my_app/t
  [write] /my_app/t/basic.t
  ...

Let's run the tests (we'll create the log directory to quiet the application output):

テストを実行してみましょう(logディレクトリを作成して、アプリケーションの出力を抑制します)。 (TBR)

  $ cd my_app
  $ mkdir log
  $ prove -lv t
  t/basic.t ..
  ok 1 - GET /
  ok 2 - 200 OK
  ok 3 - content is similar
  1..3
  ok
  All tests successful.
  Files=1, Tests=3,  0 wallclock secs ( 0.03 usr  0.01 sys +  0.33 cusr  0.07
   csys =  0.44 CPU)
  Result: PASS

The boilerplate test file looks like this:

ボイラープレートテストファイルは次のようになります。 (TBR)

  use Mojo::Base -strict;

  use Test::More;
  use Test::Mojo;

  my $t = Test::Mojo->new('MyApp');
  $t->get_ok('/')->status_is(200)->content_like(qr/Mojolicious/i);

  done_testing();

Here we can see our application class name MyApp is passed to the Test::Mojo constructor. Under the hood, Test::Mojo creates a new Mojo::Server instance, loads MyApp (which we just created), and runs the application. We write our tests with relative URLs because Test::Mojo takes care of getting the request to the running test application (since its port may change between runs).

ここでは、アプリケーションクラス名MyAppTest::Mojoコンストラクタに渡されていることがわかります。 内部では、Test::Mojoが新しいMojo::Serverインスタンスを作成し、MyApp(先ほど作成したもの)をロードしてアプリケーションを実行します。 Test::Mojoが実行中のテストアプリケーションへの要求の取得を処理するため(実行の間にポートが変更される可能性があるため)、テストは相対URLで記述します。 (TBR)

設定データのテスト

We can alter the behavior of our application using environment variables (such as MOJO_MODE) and through configuration values. One nice feature of Test::Mojo is its ability to pass configuration values directly from its constructor.

環境変数(MOJO_MODEなど)と構成値を使用して、アプリケーションの動作を変更できます。 Test::Mojoの優れた機能の1つは、構成値をコンストラクタから直接渡す機能です。 (TBR)

Let's modify our application and add a "feature flag" to enable a new feature when the enable_weather configuration value is set:

アプリケーションを変更し、enable_weather構成値が設定されたときに新しい機能を有効にする「機能フラグ」を追加しましょう。 (TBR)

  # Load configuration from hash returned by "my_app.conf"
  my $config = $self->plugin('Config');

  # Normal route to controller
  $r->get('/')->to('example#welcome');

  # NEW: this route only exists if "enable_weather" is set in the configuration
  if ($config->{enable_weather}) {
    $r->get('/weather' => sub { shift->render(text => "It's hot! 🔥") }
  }

To test this new feature, we don't even need to create a configuration file—we can simply pass the configuration data to the application directly via Test::Mojo's constructor:

この新機能をテストするには、構成ファイルを作成する必要さえなく、Test::Mojoのコンストラクタを介して構成データをアプリケーションに直接渡すだけでよい。 (TBR)

  my $t = Test::Mojo->new(MyApp => {enable_weather => 1});
  $t->get_ok('/')->status_is(200)->content_like(qr/Mojolicious/i);
  $t->get_ok('/weather')->status_is(200)->content_like(qr/🔥/);

When we run these tests, Test::Mojo will pass this configuration data to the application, which will cause it to create a special /weather route that we can access in our tests. Unless enable_weather is set in a configuration file, this route will not exist when the application runs. Feature flags like this allow us to do soft rollouts of features, targeting a small audience for a period of time. Once the feature has been proven, we can refactor the conditional and make it a full release.

これらのテストを実行すると、Test::Mojoはこの構成データをアプリケーションに渡し、テストでアクセスできる特別な/weatherルートを作成します。 構成ファイルにenable_weatherが設定されていない限り、このルートはアプリケーションの実行時には存在しません。 このような機能フラグを使用すると、一定期間、少数のオーディエンスをターゲットにして、機能のソフトロールアウトを行うことができます。 機能が証明されたら、条件をリファクタリングして完全なリリースにすることができます。 (TBR)

This example shows how easy it is to start testing a Mojolicious application and how to set specific application configuration directives from a test file.

この例では、Mojoliciousアプリケーションのテストを簡単に開始する方法と、テストファイルから特定のアプリケーション構成ディレクティブを設定する方法を示しています。 (TBR)

アプリケーションヘルパーのテスト

Let's say we register a helper in our application to generate an HTTP Basic Authorization header:

HTTP Basic Authorizationヘッダーを生成するヘルパーをアプリケーションに登録したとします。 (TBR)

  use Mojo::Util 'b64_encode';

  app->helper(basic_auth => sub {
    my ($c, @values) = @_;
    return {Authorization => 'Basic ' . b64_encode join(':' => @values), ''};
  });

How do we test application helpers like this? Test::Mojo has access to the application object, which allows us to invoke helpers from our test file:

このようなアプリケーションヘルパーをテストするにはどうすればよいでしょうか?Test::Mojoはアプリケーションオブジェクトにアクセスできるため、テストファイルからヘルパーを呼び出すことができます。 (TBR)

  my $t = Test::Mojo->new('MyApp');

  is_deeply $t->app->basic_auth(bif => "Bif's Passwerdd"),
    {Authorization => 'Basic YmlmOkJpZidzIFBhc3N3ZXJkZA=='},
    'correct header value';

Any aspect of the application (helpers, plugins, routes, etc.) can be introspected from Test::Mojo through the application object. This enables us to get deep test coverage of Mojolicious-based applications.

アプリケーションのあらゆる側面(ヘルパー、プラグイン、ルートなど)は、Test::Mojoからアプリケーションオブジェクトを通じて紹介することができる。 これにより、Mojoliciousベースのアプリケーションの深いテストカバレッジを得ることができる。 (TBR)

アサーション

This section describes the basic test assertions supplied by Test::Mojo. There are four broad categories of assertions for HTTP requests:

この項では、Test::Mojoによって提供される基本的なテストアサーションについて説明します。 HTTPリクエストのアサーションには、次の4つの大きなカテゴリがあります。 (TBR)

  • HTTP requests

  • HTTP response status

  • HTTP response headers

  • HTTP response content/body

WebSocket test assertions are covered in "Testing WebSocket web services".

WebSocketテストのアサーションについては、"Testing WebSocket Web Services"を参照してください。 (TBR)

HTTPリクエストのアサーション

Test::Mojo has a Mojo::UserAgent object that allows it to make HTTP requests and check for HTTP transport errors. HTTP request assertions include get_ok, post_ok, etc. These assertions do not test whether the request was handled successfully, only that the web application handled the request in an HTTP compliant way.

Test::Mojoには、HTTPリクエストの作成とHTTPトランスポートエラーのチェックを可能にするMojo::UserAgentオブジェクトがあります。 HTTPリクエストアサーションには、get_okpost_okなどが含まれます。 これらのアサーションは、リクエストが<正常に>処理されたかどうかをテストするのではなく、WebアプリケーションがHTTP準拠の方法でリクエストを処理したかどうかをテストするだけです。 (TBR)

You may also make HTTP requests using custom verbs (beyond GET, POST, PUT, etc.) by building your own transaction object. See "Custom transactions" below.

独自のトランザクションオブジェクトを構築することで、カスタム動詞(GETPOSTPUTなど以外)を使用してHTTPリクエストを作成することもできます。 以下の"Custom transactions"を参照してください。 (TBR)

HTTP リクエストのアサーションを使う

To post a URL-encoded form to the /calls endpoint of an application, we simply use the form content type shortcut:

URLエンコードされたフォームをアプリケーションの/callsエンドポイントに送信するには、formコンテンツタイプのショートカットを使用するだけです。 (TBR)

  $t->post_ok('/calls' => form => {to => '+43.55.555.5555'});

Which will create the following HTTP request:

これにより、次のHTTP要求が作成されます。 (TBR)

  POST /calls HTTP/1.1
  Content-Length: 20
  Content-Type: application/x-www-form-urlencoded

  to=%2B43.55.555.5555

The *_ok HTTP request assertion methods accept the same arguments as their corresponding Mojo::UserAgent methods (except for the callback argument). This allows us to set headers and build query strings for authentic test situations:

*_okHTTPリクエストアサーションメソッドは、対応するMojo::UserAgentメソッドと同じ引数を受け入れます(コールバック引数を除く)。 これにより、ヘッダーを設定し、信頼できるテスト状況のためのクエリ文字列を構築できます。 (TBR)

  $t->get_ok('/internal/personnel' => {Authorization => 'Token secret-password'}
    => form => {q => 'Professor Plum'});

which generates the following request:

これにより、次の要求が生成されます。 (TBR)

  GET /internal/personnel?q=Professor+Plum HTTP/1.1
  Content-Length: 0
  Authorization: Token secret-password

The form content generator (see Mojo::UserAgent::Transactor) will generate a query string for GET requests and application/x-www-form-urlencoded or multipart/form-data for POST requests.

formコンテンツジェネレーター(Mojo::UserAgent::Transactorを参照)は、GET要求に対しては照会ストリングを生成し、POST要求に対してはapplication/x-www-form-urlencodedまたはmultipart/form-dataを生成します。 (TBR)

While these *_ok assertions make the HTTP requests we expect, they tell us little about how well the application handled the request. The application we're testing might have returned any content-type, body, or HTTP status code (200, 302, 400, 404, 500, etc.) and we wouldn't know it.

これらの*_okアサーションは、私たちが期待するHTTP リクエストを作成しますが、アプリケーションがリクエストを<どれだけうまく>処理したかについてはほとんど教えてくれません。 私たちがテストしているアプリケーションは、任意のコンテンツタイプ、ボディ、またはHTTPステータスコード(200、302、400、404、500など)を返した可能性があり、私たちはそれを知ることができません。 (TBR)

Test::Mojo provides assertions to test almost every aspect of the HTTP response, including the HTTP response status code, the value of the Content-Type header, and other arbitrary HTTP header information.

Test::Mojoは、HTTPレスポンスのステータスコード、Content-Typeヘッダーの値、その他の任意のHTTPヘッダー情報など、HTTPレスポンスのほぼすべての側面をテストするためのアサーションを提供する。 (TBR)

HTTPレスポンスステータスコード

While not technically an HTTP header, the status line is the first line in an HTTP response and is followed by the response headers. Testing the response status code is common in REST-based and other web applications that use the HTTP status codes to broadly indicate the type of response the server is returning.

技術的にはHTTPヘッダーではありませんが、ステータス行はHTTPレスポンスの最初の行であり、その後にレスポンスヘッダーが続きます。 レスポンスステータスコードのテストは、HTTPステータスコードを使用してサーバーが返すレスポンスのタイプを広く示すRESTベースやその他のWebアプリケーションで一般的です。 (TBR)

Testing the status code is as simple as adding the status_is assertion:

ステータスコードのテストは、Cの<status_is>アサーションを追加するだけの簡単なものです。 (TBR)

  $t->post_ok('/doorbell' => form => {action => 'ring once'})
    ->status_is(200);

Along with status_isnt, this will cover most needs. For more elaborate status code testing, you can access the response internals directly:

status_isntとともに、これはほとんどのニーズをカバーします。 より詳細なステータスコードテストのために、応答内部に直接アクセスできます。 (TBR)

  $t->post_ok('/doorbell' => form => {action => 'ring once'});
  is $t->tx->res->message, 'Moved Permanently', 'try next door';

HTTPレスポンスヘッダ

Test::Mojo allows us to inspect and make assertions about HTTP response headers. The Content-Type header is commonly tested and has its own assertion:

Test::Mojoを使用すると、HTTPレスポンスヘッダーを検査して アサーションを作成できます。 Content-Typeヘッダーは一般的にテストされ、独自のアサーションがあります:

  $t->get_ok('/map-of-the-world.pdf')
    ->content_type_is('application/pdf');

This is equivalent to the more verbose:

これは、より冗長な次のものと等価です:

  $t->get_ok('/map-of-the-world.pdf')
    ->header_is('Content-Type' => 'application/pdf');

We can test for multiple headers in a single response using method chains:

メソッドチェーンを使用して、一つの応答で複数のヘッダーをテストできます:

  $t->get_ok('/map-of-the-world.pdf')
    ->content_type_is('application/pdf')
    ->header_isnt('Compression' => 'gzip')
    ->header_unlike('Server' => qr/IIS/i);

HTTPレスポンスの内容のアサーション

Test::Mojo also exposes a rich set of assertions for testing the body of a response, whether that body be HTML, plain-text, or JSON. The content_* methods look at the body of the response as plain text (as defined by the response's character set):

Test::Mojoは、応答の本文がHTML、プレーンテキスト、JSONのいずれであっても、 その本文をテストするための豊富なアサーションのセットも公開しています。 content_*メソッドは、応答の本文をプレーンテキスト(応答の文字セットで 定義されている)として見ます:

  $t->get_ok('/scary-things/spiders.json')
    ->content_is('{"arachnid":"brown recluse"}');

Although this is a JSON document, content_is treats it as if it were a text document. This may be useful for situations where we're looking for a particular string and not concerned with the structure of the document. For example, we can do the same thing with an HTML document:

これはJSON文書ですが、content_isはそれをテキスト文書のように扱います。 これは、特定の文字列を探していて、文書の構造に関係しない 状況で役立つ場合があります。 たとえば、HTML文書で同じことを行うことができます:

  $t->get_ok('/scary-things/spiders.html')
    ->content_like(qr{<title>All The Spiders</title>});

But because Test::Mojo has access to everything that Mojo::UserAgent does, we can introspect JSON documents as well as DOM-based documents (HTML, XML) with assertions that allow us to check for the existence of elements as well as inspect the content of text nodes.

しかし、Test::MojoMojo::UserAgentが行うすべてのことに アクセスできるため、要素の存在をチェックし、テキストノードの内容を 検査することを可能にするアサーションを使用して、DOMベースの文書 (HTML、XML)だけでなくJSON文書もイントロスペクションすることができます。

JSONレスポンスのアサーション

Test::Mojo's Mojo::UserAgent has access to a JSON parser, which allows us to test to see if a JSON response contains a value at a location in the document using JSON pointer syntax:

Test::MojoMojo::UserAgentはJSONパーサにアクセスできるため、JSONポインタ構文を使用して、JSON応答に文書内の場所の値が含まれているかどうかをテストすることができる。 (TBR)

  $t->get_ok('/animals/friendly.json')
    ->json_has('/beings/jeremiah/age');

This assertion tells us that the friendly.json document contains a value at the /beings/jeremiah/age JSON pointer location. We can also inspect the value at JSON pointer locations:

このアサーションは、friendly.json文書に/exists/jeremiah/ageJSONポインタの場所に値が含まれていることを示します。 JSONポインタの場所で値を検査することもできます。 (TBR)

  $t->get_ok('/animals/friendly.json')
    ->json_has('/beings/jeremiah/age')
    ->json_is('/beings/jeremiah/age' => 42)
    ->json_like('/beings/jeremiah/species' => qr/bullfrog/i);

JSON pointer syntax makes testing JSON responses simple and readable.

JSONポインター構文を使用すると、JSONレスポンスのテストが簡単で読みやすくなります。 (TBR)

DOMレスポンスのアサーション

We can also inspect HTML and XML responses using the Mojo::DOM parser in the user agent. Here are a few examples from the Test::Mojo documentation:

また、ユーザーエージェントのMojo::DOMパーサーを使用して、HTMLおよびXMLの応答を検査することもできます。 Test::Mojoの文書からいくつかの例を示します。 (TBR)

  $t->text_is('div.foo[x=y]' => 'Hello!');
  $t->text_is('html head title' => 'Hello!', 'right title');

The Mojo::DOM parser uses the CSS selector syntax described in Mojo::DOM::CSS, allowing us to test for values in HTML and XML documents without resorting to typically verbose and inflexible DOM traversal methods.

Mojo::DOMパーサーは、Mojo::DOM::CSSで説明されているCSSセレクタ構文を使用します。 (TBR)

ADVANCED TOPICS

This section describes some complex (but common) testing situations that Test::Mojo excels in making simple.

このセクションでは、Test::Mojoがシンプルにするのに優れている、複雑な(しかし一般的な)テスト状況について説明する。 (TBR)

リダイレクト

The Mojo::UserAgent object in Test::Mojo can handle HTTP redirections internally to whatever level you need. Let's say we have a web service that redirects /1 to /2, /2 redirects to /3, /3 redirects to /4, and /4 redirects to /5:

Test::MojoMojo::UserAgentオブジェクトは、必要なレベルまで内部的にHTTPリダイレクションを処理できます。 /1/2にリダイレクトし、/2/3にリダイレクトし、/3/4にリダイレクトし、/4/5にリダイレクトするWebサービスがあるとします。 (TBR)

  GET /1

returns:

これは次を返し:

  302 Found
  Location: /2

and:

そして:

  GET /2

returns:

これは次を返し:

  302 Found
  Location: /3

and so forth, up to /5:

以下、/5まで:

  GET /5

which returns the data we wanted:

必要なデータが返されます:

  200 OK

  {"message":"this is five"}

We can tell the user agent in Test::Mojo how to deal with redirects. Each test is making a request to GET /1, but we vary the number of redirects the user agent should follow with each test:

Test::Mojoのユーザーエージェントにリダイレクトの処理方法を伝えることができます。 各テストはGET /1に要求を行いますが、ユーザーエージェントが各テストで従うべきリダイレクトの数は異なります。 (TBR)

  my $t = Test::Mojo->new;

  $t->get_ok('/1')
    ->header_is(location => '/2');

  $t->ua->max_redirects(1);
  $t->get_ok('/1')
    ->header_is(location => '/3');

  $t->ua->max_redirects(2);
  $t->get_ok('/1')
    ->header_is(location => '/4');

  # Look at the previous hop
  is $t->tx->previous->res->headers->location, '/3', 'previous redirect';

  $t->ua->max_redirects(3);
  $t->get_ok('/1')
    ->header_is(location => '/5');

  $t->ua->max_redirects(4);
  $t->get_ok('/1')
    ->json_is('/message' => 'this is five');

When we set max_redirects, it stays set for the life of the test object until we change it.

max_redirectsを設定すると、変更するまでテストオブジェクトの存続期間中、設定されたままになります。 (TBR)

Test::Mojo's handling of HTTP redirects eliminates the need for making many, sometimes an unknown number, of redirections to keep testing precise and easy to follow (ahem).

Test::MojoのHTTPリダイレクトの処理により、テストを正確かつ容易に実行し続けるために、多くの(時には未知の数の)リダイレクションを行う必要がなくなります。 (TBR)

クッキーとセッション管理

We can use Test::Mojo to test applications that keep session state in cookies. By default, the Mojo::UserAgent object in Test::Mojo will manage session for us by saving and sending cookies automatically, just like common web browsers:

Test::Mojoを使用して、セッションステートをCookieに保持するアプリケーションをテストできます。 デフォルトでは、Test::MojoMojo::UserAgentオブジェクトは、一般的なWebブラウザと同様に、Cookieを自動的に保存および送信することによってセッションを管理します。 (TBR)

  use Mojo::Base -strict;

  use Test::More;
  use Test::Mojo;

  my $t = Test::Mojo->new('MyApp');

  # No authorization cookie
  $t->get_ok('/')
    ->status_is(401)
    ->content_is('Please log in');

  # Application sets an authorization cookie
  $t->post_ok('/login' => form => {password => 'let me in'})
    ->status_is(200)
    ->content_is('You are logged in');

  # Sends the cookie from the previous transaction
  $t->get_ok('/')
    ->status_is(200)
    ->content_like(qr/You logged in at \d+/);

  # Clear the cookies
  $t->reset_session;

  # No authorization cookie again
  $t->get_ok('/')
    ->status_is(401)
    ->content_is('Please log in');

We can also inspect cookies in responses for special values through the transaction's response (Mojo::Message::Response) object:

また、トランザクションの応答(Mojo::Message::Response)オブジェクトを使用して、応答内のクッキーに特別な値があるかどうかを検査することもできます。 (TBR)

  $t->get_ok('/');
  like $t->tx->res->cookie('smarty'), qr/smarty=pants/, 'cookie found';

カスタムトランザクション

Let's say we have an application that responds to a new HTTP verb RING and to use it we must also pass in a secret cookie value. This is not a problem. We can test the application by creating a Mojo::Transaction object, setting the cookie (see Mojo::Message::Request), then passing the transaction object to request_ok:

新しいHTTP動詞RINGに応答するアプリケーションがあり、それを使用するために秘密のクッキー値も渡す必要があるとします。 これは問題ではありません。 アプリケーションをテストするには、Mojo::Transactionオブジェクトを作成し、クッキーを設定し(Mojo::Message::Requestを参照)、トランザクションオブジェクトをrequest_okに渡します。 (TBR)

  # Use custom "RING" verb
  my $tx = $t->ua->build_tx(RING => '/doorbell');

  # Set a special cookie
  $tx->req->cookies({name => 'Secret', value => "don't tell anybody"});

  # Make the request
  $t->request_ok($tx)
    ->status_is(200)
    ->json_is('/status' => 'ding dong');

WebSocket web サービスのテスト

While the message flow on WebSocket connections can be rather dynamic, it more often than not is quite predictable, which allows this rather pleasant Test::Mojo WebSocket API to be used:

WebSocket接続上のメッセージフローはかなり動的であるが、多くの場合、かなり予測可能であるため、このかなり快適なTest::MojoWebSocket APIを使用できる。 (TBR)

  use Mojo::Base -strict;

  use Test::More;
  use Test::Mojo;

  # Test echo web service
  my $t = Test::Mojo->new('EchoService');
  $t->websocket_ok('/echo')
    ->send_ok('Hello Mojo!')
    ->message_ok
    ->message_is('echo: Hello Mojo!')
    ->finish_ok;

  # Test JSON web service
  $t->websocket_ok('/echo.json')
    ->send_ok({json => {test => [1, 2, 3]}})
    ->message_ok
    ->json_message_is('/test' => [1, 2, 3])
    ->finish_ok;

  done_testing();

Because of their inherent asynchronous nature, testing WebSocket communications can be tricky. The Test::Mojo WebSocket assertions serialize messages via event loop primitives. This enables us to treat WebSocket messages as if they were using the same request-response communication pattern we're accustomed to with HTTP.

Test::MojoWebSocketアサーションは、イベントループプリミティブを介してメッセージをシリアライズします。 これにより、WebSocketメッセージを、HTTPで慣れ親しんだ同じ要求-応答コミュニケーションパターンを使用しているかのように扱うことができます。 (TBR)

To illustrate, let's walk through these tests. In the first test, we use the websocket_ok assertion to ensure that we can connect to our application's WebSocket route at /echo and that it's "speaking" WebSocket protocol to us. The next send_ok assertion tests the connection again (in case it closed, for example) and attempts to send the message Hello Mojo!. The next assertion, message_ok, blocks (using the Mojo::IOLoop singleton in the application) and waits for a response from the server. The response is then compared with 'echo: Hello Mojo!' in the message_is assertion, and finally we close and test our connection status again with finish_ok.

説明のために、これらのテストを見てみましょう。 最初のテストでは、WebSocket_okアサーションを使用して、アプリケーションのWebSocketルートに/echoで接続できること、およびWebSocketプロトコルを「話している」ことを確認します。 次のsend_okアサーションは、接続を再度テストし(たとえば、接続が閉じた場合)、メッセージHello Mojo!を送信しようとします。 次のアサーションであるmessage_okは、(アプリケーション内のMojo::IOLoopシングルトンを使用して)ブロックし、サーバからの応答を待ちます。 次に、応答はmessage_isアサーション内の'echo: Hello Mojo!'と比較され、最後に、finish_okで接続ステータスを再度テストします。 (TBR)

The second test is like the first, but now we're sending and expecting JSON documents at /echo.json. In the send_ok assertion we take advantage of Mojo::UserAgent's JSON content generator (see Mojo::UserAgent::Transactor) to marshal hash and array references into JSON documents, and then send them as a WebSocket message. We wait (block) for a response from the server with message_ok. Then because we're expecting a JSON document back, we can leverage json_message_ok which parses the WebSocket response body and returns an object we can access through Mojo::JSON::Pointer syntax. Then we close (and test) our WebSocket connection.

2番目のテストは最初のテストと似ていますが、現在は/echo.jsonでJSON文書を送信して期待しています。 send_okアサーションでは、Mojo::UserAgentのJSONコンテンツジェネレータ(Mojo::UserAgent::Transactorを参照)を利用して、ハッシュと配列参照をJSON文書にマーシャリングし、WebSocketメッセージとして送信します。 message_okでサーバからの応答を待ちます(ブロックします)。 次に、JSON文書が返されることを期待しているため、WebSocket応答本体を解析し、Mojo::JSON::Pointer構文を通じてアクセスできるオブジェクトを返すjson_message_okを活用できます。 次に、WebSocket接続を閉じます(そしてテストします)。 (TBR)

Testing WebSocket servers does not get any simpler than with Test::Mojo.

WebSocketサーバのテストは、Test::Mojoよりも簡単にはなりません。

Extending Test::Mojo

(Test::Mojo の拡張)

If you see that you're writing a lot of test assertions that aren't chainable, you may benefit from writing your own test assertions. Let's say we want to test the Location header after a redirect. We'll create a new class with Role::Tiny that implements a test assertion named location_is:

チェーン化できないテストアサーションを大量に作成している場合は、独自のテストアサーションを作成すると便利です。 リダイレクト後にLocationヘッダーをテストするとします。 location_isという名前のテストアサーションを実装するRole::Tinyを持つ新しいクラスを作成します。 (TBR)

  package Test::Mojo::Role::Location;
  use Mojo::Base -role;

  use Test::More;

  sub location_is {
    my ($t, $value, $desc) = @_;
    $desc ||= "Location: $value";
    local $Test::Builder::Level = $Test::Builder::Level + 1;
    return $t->success(is($t->tx->res->headers->location, $value, $desc));
  }

  1;

When we make new test assertions using roles, we want to use method signatures that match other *_is methods in Test::Mojo, so here we accept the test object, the value to compare, and an optional description.

ロールを使用して新しいテストアサーションを作成する場合、Test::Mojo内の他の*_isメソッドと一致するメソッドシグネチャを使用する必要があるため、ここではテストオブジェクト、比較する値、およびオプションの説明を受け入れる。 (TBR)

We assign a default description value ($desc), set the Test::Builder Level global variable one level higher (which tells Test::Builder how far up the call stack to look when something fails), then we use Test::More's is function to compare the location header with the expected header value. We wrap that in the success attribute, which records the boolean test result and propagates the Test::Mojo object for method chaining.

デフォルトの記述値($desc)を割り当て、Test::BuilderLevelグローバル変数を1レベル上に設定し(これにより、Test::Builderは、何かが失敗したときに呼び出しスタックのどこまで調べるかを指定します)、Test::Moreis関数を使用して、ロケーションヘッダーを予想されるヘッダー値と比較します。 これをsuccess属性にラップします。 この属性は、ブールテスト結果を記録し、メソッドチェーン用のTest::Mojoオブジェクトを伝播します。 (TBR)

With this new package, we're ready to compose a new test object that uses the role:

この新しいパッケージを使用して、ロールを使用する新しいテストオブジェクトを作成する準備が整いました。 (TBR)

  my $t = Test::Mojo->with_roles('+Location')->new('MyApp');

  $t->post_ok('/redirect/mojo' => json => {message => 'Mojo, here I come!'})
    ->status_is(302)
    ->location_is('http://mojolicious.org')
    ->or(sub { diag 'I miss tempire.' });

In this section we've covered how to add custom test assertions to Test::Mojo with roles and how to use those roles to simplify testing.

このセクションでは、ロールを使用してTest::Mojoにカスタムテストアサーションを追加する方法と、それらのロールを使用してテストを簡素化する方法について説明しました。 (TBR)

MORE

You can continue with Mojolicious::Guides now or take a look at the Mojolicious wiki, which contains a lot more documentation and examples by many different authors.

Mojolicious::Guidesを今すぐ続けることも、Mojolicious wikiを見ることもできます。 このMojolicious wikiには、さまざまな著者による多くの文書と例が含まれています。 (TBR)

サポート

If you have any questions the documentation might not yet answer, don't hesitate to ask on the mailing list or the official IRC channel #mojo on irc.freenode.net (chat now!).

文書でまだ回答されていない質問がある場合は、mailing listまたはirc.freenode.netの公式IRCチャネル#mojo(chat now!)で遠慮なく質問してください。