CodeIgniter4のフィーチャーテスト
この記事は CodeIgniter Advent Calendar 2020 - Qiita の14日目です。まだ、空きがありますので、興味のある方は気軽に参加してください。
フィーチャーテストとは?
CodeIgniter4 にはフィーチャーテストの機能が含まれています。
フィーチャーテストは Web アプリへのリクエストサイクル全体をテストする結合テストで、ci-phpunit-test での $this->request() に相当するものです。
Web アプリにリクエストを擬似的に送信し、その結果についてテストするということで、直感的にわかりやすいものです。
テストのための設定
プロジェクトルートに PHPUnit の設定ファイル phpunit.xml.dist
があります。これを、phpunit.xml
としてコピーし、自分の環境に合うように変更します。
app.baseURL
は .env
で設定していますので削除します。
--- phpunit.xml.dist 2020-12-14 09:16:19.000000000 +0900
+++ phpunit.xml 2020-12-14 09:16:19.000000000 +0900
@@ -36,8 +36,6 @@
</logging>
<php>
- <server name="app.baseURL" value="http://example.com"/>
-
<!-- Directory containing phpunit.xml -->
<const name="HOMEPATH" value="./"/>
phpunit.xml
はプロジェクトで共有するので、git add -f
で追加してバージョン管理しましょう。
テストファイルの作成
Welcome ページをリクエストするテストを作成してみましょう。
tests/feature
フォルダを作成し、tests/feature/HomeTest.php
を作成します。
tests/feature/HomeTest.php
<?php
namespace Tests\Feature;
use CodeIgniter\Test\FeatureTestCase;
class HomeTest extends FeatureTestCase
{
public function testGetIndex()
{
$result = $this->call('get', '/');
dd($result);
}
}
GET メソッドでパス /
に、リクエストを送信するコードです。
dd()
関数で、取得した結果を表示してみます。
返り値の確認
テストを実行してみましょう。
$ vendor/bin/phpunit tests/feature/HomeTest.php
PHPUnit 8.5.13 by Sebastian Bergmann and contributors.
Error: XDEBUG_MODE=coverage or xdebug.mode=coverage has to be set
┌──────────────────────────────────────────────────────────────────────────────┐
│ $result │
└──────────────────────────────────────────────────────────────────────────────┘
CodeIgniter\Test\FeatureResponse (45) (
public 'response' -> CodeIgniter\HTTP\Response (17) (
protected 'reason' -> string (2) "OK"
protected 'statusCode' -> integer 200
protected 'CSPEnabled' -> boolean false
public 'CSP' -> CodeIgniter\HTTP\ContentSecurityPolicy (22) (
protected 'baseURI' -> null
protected 'childSrc' -> string (4) "self"
protected 'connectSrc' -> string (4) "self"
protected 'defaultSrc' -> null
protected 'fontSrc' -> null
protected 'formAction' -> string (4) "self"
protected 'frameAncestors' -> null
protected 'imageSrc' -> string (4) "self"
protected 'mediaSrc' -> null
protected 'objectSrc' -> string (4) "self"
protected 'pluginTypes' -> null
protected 'reportURI' -> null
protected 'sandbox' -> null
protected 'scriptSrc' -> string (4) "self"
protected 'styleSrc' -> string (4) "self"
protected 'manifestSrc' -> null
protected 'upgradeInsecureRequests' -> boolean false
protected 'reportOnly' -> boolean false
protected 'validSources' -> array (4) [
0 => string (4) "self"
1 => string (4) "none"
2 => string (13) "unsafe-inline"
3 => string (11) "unsafe-eval"
]
protected 'nonces' -> array (0) []
protected 'tempHeaders' -> array (0) []
protected 'reportOnlyHeaders' -> array (0) []
)
protected 'cookiePrefix' -> string (0) ""
protected 'cookieDomain' -> string (0) ""
protected 'cookiePath' -> string (1) "/"
protected 'cookieSecure' -> boolean false
protected 'cookieHTTPOnly' -> boolean false
protected 'cookies' -> array (0) []
protected 'pretend' -> boolean false
protected 'bodyFormat' -> string (4) "html"
protected 'headers' -> array (2) [
'Cache-control' => CodeIgniter\HTTP\Header (2) (
protected 'name' -> string (13) "Cache-control"
protected 'value' -> array (3) [
0 => string (8) "no-store"
1 => string (9) "max-age=0"
2 => string (8) "no-cache"
]
)
'Content-Type' => CodeIgniter\HTTP\Header (2) (
protected 'name' -> string (12) "Content-Type"
protected 'value' -> string (24) "text/html; charset=UTF-8"
)
]
protected 'headerMap' -> array (2) [
'cache-control' => string (13) "Cache-control"
'content-type' => string (12) "Content-Type"
]
protected 'protocolVersion' -> string (3) "1.1"
protected 'validProtocolVersions' -> array (3) [
0 => string (3) "1.0"
1 => string (3) "1.1"
2 => string (1) "2"
]
protected 'body' -> string (18385) "<!-- DEBUG-VIEW START 1 APPPATH/Config/../Views/welcome_message.php -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Welcome to CodeIgniter 4!</title>
<meta name="description" content="The small framework with powerful features">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="shortcut icon" type="image/png" href="/favicon.ico"/>
<!-- STYLES -->
<style {csp-style-nonce}>
...
</style>
</head>
<body>
<!-- HEADER: MENU + HEROE SECTION -->
<header>
<div class="menu">
<ul>
<li class="logo"><a href="https://codeigniter.com" target="_blank"><img height="44" title="CodeIgniter Logo"
alt="Visit CodeIgniter.com official website!"
src="data:image/png;base64,..."></a>
</li>
<li class="menu-toggle">
<button onclick="toggleMenu();">☰</button>
</li>
<li class="menu-item hidden"><a href="#">Home</a></li>
<li class="menu-item hidden"><a href="https://codeigniter4.github.io/userguide/" target="_blank">Docs</a>
</li>
<li class="menu-item hidden"><a href="https://forum.codeigniter.com/" target="_blank">Community</a></li>
<li class="menu-item hidden"><a
href="https://github.com/codeigniter4/CodeIgniter4/blob/master/CONTRIBUTING.md" target="_blank">Contribute</a>
</li>
</ul>
</div>
<div class="heroe">
<h1>Welcome to CodeIgniter 4.0.4</h1>
<h2>The small framework with powerful features</h2>
</div>
</header>
<!-- CONTENT -->
<section>
<h1>About this page</h1>
<p>The page you are looking at is being generated dynamically by CodeIgniter.</p>
<p>If you would like to edit this page you will find it located at:</p>
<pre><code>app/Views/welcome_message.php</code></pre>
<p>The corresponding controller for this page can be found at:</p>
<pre><code>app/Controllers/Home.php</code></pre>
</section>
<div class="further">
<section>
<h1>Go further</h1>
<h2>
<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'>...</svg>
Learn
</h2>
<p>The User Guide contains an introduction, tutorial, a number of "how to"
guides, and then reference documentation for the components that make up
the framework. Check the <a href="https://codeigniter4.github.io/userguide"
target="_blank">User Guide</a> !</p>
<h2>
<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'>...</svg>
Discuss
</h2>
<p>CodeIgniter is a community-developed open source project, with several
venues for the community members to gather and exchange ideas. View all
the threads on <a href="https://forum.codeigniter.com/"
target="_blank">CodeIgniter's forum</a>, or <a href="https://codeigniterchat.slack.com/"
target="_blank">chat on Slack</a> !</p>
<h2>
<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'>...</svg>
Contribute
</h2>
<p>CodeIgniter is a community driven project and accepts contributions
of code and documentation from the community. Why not
<a href="https://codeigniter.com/en/contribute" target="_blank">
join us</a> ?</p>
</section>
</div>
<!-- FOOTER: DEBUG INFO + COPYRIGHTS -->
<footer>
<div class="environment">
<p>Page rendered in 0.0181 seconds</p>
<p>Environment: testing</p>
</div>
<div class="copyrights">
<p>© 2020 CodeIgniter Foundation. CodeIgniter is open source project released under the MIT
open source licence.</p>
</div>
</footer>
...
</body>
</html>
<!-- DEBUG-VIEW ENDED 1 APPPATH/Config/../Views/welcome_message.php -->
"
)
protected 'domParser' -> CodeIgniter\Test\DOMParser (1) (
protected 'dom' -> DOMDocument (0) ()
)
protected 'backupGlobals' -> null
protected 'backupGlobalsBlacklist' -> array (0) []
protected 'backupStaticAttributes' -> null
protected 'backupStaticAttributesBlacklist' -> array (0) []
protected 'runTestInSeparateProcess' -> null
protected 'preserveGlobalState' -> boolean true
private 'runClassInSeparateProcess' -> null
private 'inIsolation' -> boolean false
private 'data' -> null
private 'dataName' -> null
private 'expectedException' -> null
private 'expectedExceptionMessage' -> null
private 'expectedExceptionMessageRegExp' -> null
private 'expectedExceptionCode' -> null
private 'name' -> string (0) ""
private 'dependencies' -> array (0) []
private 'dependencyInput' -> array (0) []
private 'iniSettings' -> array (0) []
private 'locale' -> array (0) []
private 'mockObjects' -> array (0) []
private 'mockObjectGenerator' -> null
private 'status' -> integer -1
private 'statusMessage' -> string (0) ""
private 'numAssertions' -> integer 0
private 'result' -> null
private 'testResult' -> null
private 'output' -> string (0) ""
private 'outputExpectedRegex' -> null
private 'outputExpectedString' -> null
private 'outputCallback' -> boolean false
private 'outputBufferingActive' -> boolean false
private 'outputBufferingLevel' -> null
private 'outputRetrievedForAssertion' -> boolean false
private 'snapshot' -> null
private 'prophet' -> null
private 'beStrictAboutChangesToGlobalState' -> boolean false
private 'registerMockObjectsFromTestArgumentsRecursively' -> boolean false
private 'warnings' -> array (0) []
private 'groups' -> array (0) []
private 'doesNotPerformAssertions' -> boolean false
private 'customComparators' -> array (0) []
private 'doubledTypes' -> array (0) []
private 'deprecatedExpectExceptionMessageRegExpUsed' -> boolean false
)
════════════════════════════════════════════════════════════════════════════════
Called from <ROOT>/tests/feature/HomeTest.php:12 [dd()]
$this->call()
は CodeIgniter\Test\FeatureResponse
オブジェクトを返す。その response
プロパティに CodeIgniter\HTTP\Response
オブジェクトが含まれていることがわかります。
テストコードの作成
流れがわかりましたので、テストコードを作成していきましょう。
HTTP ステータスやレスポンスに含まれる文字列を検証します。
tests/feature/HomeTest.php
<?php
namespace Tests\Feature;
use CodeIgniter\Test\FeatureTestCase;
class HomeTest extends FeatureTestCase
{
public function testGetIndex()
{
$result = $this->call('get', '/');
// dd($result);
$result->assertStatus(200);
$result->assertSee('<title>Welcome to CodeIgniter 4!</title>');
$result->assertSee('Environment: testing');
}
}
ステータスコードが 200 であることと、<title>
タグの文字列、それと環境が testing
になっていることを確認します。
テストの実行
phpunit
を実行します。
$ vendor/bin/phpunit tests/feature/HomeTest.php
PHPUnit 8.5.13 by Sebastian Bergmann and contributors.
Error: XDEBUG_MODE=coverage or xdebug.mode=coverage has to be set
. 1 / 1 (100%)
Time: 302 ms, Memory: 10.00 MB
OK (1 test, 3 assertions)
通りました。
テスト実行中は CodeIgniter4 の環境が testing
になっていることも確認できました。
CodeIgniter4のフィーチャーテストでデータベースを使う に続きます。
この記事は CodeIgniter Advent Calendar 2020 - Qiita の14日目です。まだ、空きがありますので、興味のある方は気軽に参加してください。
参考
Date: 2020/12/14