PHPUnit – The PHP Testing Framework
インストールする方法はいくつかあります。
Homebrewを使いインストールする方法とpharファイルをwget/curlでインストールする方法を記載します。
$ brew search phpunit | grep phpunit
// homebrew/php/phpunit
// homebrew/php/phpunit-skeleton-generator
// homebrew/php/phpunit@5.7
$ brew install phpunit
$ wget https://phar.phpunit.de/phpunit.phar
$ chmod +x phpunit.phar
$ sudo mv phpunit.phar /usr/local/bin/phpunit
$ phpunit --version
$ phpunit ExampleTest // ワーキングディレクトリのExampleTest.phpを実行
$ phpunit -c phpunit.xml // 設定ファイル指定
$ phpunit -c dir // 設定ファイルのあるディレクトリを指定
$ phpunit --group=hoge // groupアノテーションを指定したテスト実行
$ phpunit --exclude-group=hoge // 除外グループを指定して実行
$ phpunit --debug // デバッグ情報を表示
$ phpunit --verbose // 詳細な説明を表示
$ phpunit --coverage-html </path/to/directory> // directoryへhtml形式のカバレッジ出力
--configuration が設定 されていない場合は、現在の作業ディレクトリから phpunit.xml あるいは phpunit.xml.dist を (この順に) 探し、 見つかった場合はそれを自動的に読み込みます。
テストを作成するときには、テストを何らかの条件で分類しておくと便利です。この分類をテストスイートと呼びます。
「Symfony2 入門」(p250)
phpunit.xmlでテストスイートを定義できます。
<testsuites>
<testsuite name="unit">
<directory>/path/to/tests/unit</directory>
</testsuite>
<testsuite name="functional">
<directory>/path/to/tests/functional</directory>
</testsuite>
<testsuite name="all">
<directory>/path/to/tests</directory>
</testsuite>
</testsuites>
テストスイートの実行。
$ phpunit --testsuite=unit
$ phpunit --testsuite=functional
$ phpunit --testsuite=all
<filter>
<whitelist>
<directory suffix=".php">/path/to/dirctory</directory>
<file>/path/to/file</file>
<exclude>
<directory suffix=".php">/path/to/directory</directory>
<file>/path/to/file</file>
</exclude>
</whitelist>
</filter>
PHPUnit マニュアル – 付録C XML 設定ファイル
whitelistタグにprocessUncoveredFilesFromWhitelist属性を指定できますが、
指定したときにカバレッジを作成できないことがありました。
PHPUnit マニュアル – 第11章 コードカバレッジ解析
phpunit.xmlへログlを指定することで実行時にオプションの指定を省略できます。
<logging>
<log type="coverage-html" target="/tmp/report" lowUpperBound="35"
highLowerBound="70"/>
<log type="coverage-clover" target="/tmp/coverage.xml"/>
<log type="coverage-php" target="/tmp/coverage.serialized"/>
<log type="coverage-text" target="php://stdout" showUncoveredFiles="false"/>
<log type="junit" target="/tmp/logfile.xml" logIncompleteSkipped="false"/>
<log type="testdox-html" target="/tmp/testdox.html"/>
<log type="testdox-text" target="/tmp/testdox.txt"/>
</logging>
PHPUnit は、準備用のコードの共有をサポートしています。 各テストメソッドが実行される前に、setUp() という名前のテンプレートメソッドが実行されます。setUp() は、テスト対象のオブジェクトを生成するような処理に使用します。 テストメソッドの実行が終了すると、それが成功したか否かにかかわらず、 tearDown() という名前の別のテンプレートメソッドが実行されます。 tearDown() では、テスト対象のオブジェクトの後始末などを行います。
「各メソッドが実行される前に」実行されます。クラスファイルで1回ではありません。
class SetupTest extends \PHPUnit_Framework_TestCase
{
function setUp() {
var_dump(date('Y-m-d H:i:s'));
}
/**
* @test
*/
function テスト1() {
$this->assertTrue(true);
}
/**
* @test
*/
function テスト2() {
$this->assertTrue(true);
}
}
上記の例では2個メソッドがあるのでsetUpは2回実行されます。
アノテーション@expectedException(および関連するアノテーション)を使い例外をテストします。
<?php
class HelloWorld
{
public function get($type = '')
{
if (strtolower($type) === 'exception') {
throw new \Exception('例外発生。', '8');
}
return 'Hello World';
}
<?php
require_once 'HelloWorld.php';
class HelloWorldTest extends \PHPUnit_Framework_TestCase
{
/**
* 例外テスト
*
* @test
* @expectedException \Exception
* @expectedExceptionCode 8
* @expectedExceptionMessage 例外発生
*/
public function 例外のテスト() {
$o = new HelloWorld();
$o->get('exception');
}
/**
* 正常テスト
* @test
*/
public function 正常テスト() {
$o = new HelloWorld();
$this->assertThat($o->get(), $this->equalTo('Hello World'));
}
}
クラス | メソッド | 戻り値型 |
---|---|---|
\PHPUnit_Framework_TestCase | getMockBuilder | \PHP_Framework_MockObject_MockBuilder |
\PHP_Framework_MockObject_MockBuilder | getMock | \PHP_Framework_MockObject_MockObject |
モックを使った簡単なサンプルを記載します。
モックの対象となるクラス。
class Server
{
public function execute() {
$data = .........
// 通信などの重い処理
return $data;
}
}
モックを使用してテストされるクラス(SUT)
class Client
{
public function execute(Server $server) {
$data = $server->execute();
return 'Mock Test: ' . $data;
}
}
モックを使用したテスト。
<?php
use appBundle\Service\Client;
use AppBundle\Service\Server;
class ClientTest extends \PHPUnit_Framework_TestCase
{
/**
* @test
*/
public function レスポンスが正しいこと()
{
$client = new Client();
/**
* @var \PHPUnit_Framework_MockObject_MockObject $mock
*/
$mock = $this->getMockBuilder(Server::class)->getMock();
$mock->expects($this->once())
->method('execute')
->willReturn('Hello World!');
$response = $client->execute($mock);
$this->assertThat($response, $this->equalTo('Mock Test: Hello World!');
}
}
メソッド | 内容 |
---|---|
will('foo') | モックからの返却する値 |
willReturn | will($this->returnValue('foo')) |
will($value)はwill($this->returnValue($value))と同じです。
例外を返す。
// SomeClass クラスのスタブを作成します
$stub = $this->createMock(SomeClass::class);
// スタブの設定を行います
$stub->method('doSomething')
->will($this->throwException(new Exception));
モックを使用してテストするクラス(上記例ではClient)をSUT(system under test)と呼ぶことがあります。
基本はパブリックメソッドのテストでカバーしますが、
プライベートメソッドのテストが必要なときはリフレクションを使います。
テスト対象。
namespace \My\Package
class Example {
private examplePrivateMethod($a, $b) {
}
}
テスト。
<?php
use \My\Package\Example;
class ExampleTest extends PHPUnit_Framework_TestCase
{
/**
* @group relativePath
*/
public function testExamplePrivateMethod()
$obj = new Example();
$method = new \ReflectionMethod(get_class($obj), 'examplePrivateMethod');
$method->setAccessible(true);
$actual = $method->invoke($obj, '第1引数', '第2引数'); // invokeの第1引数は対象クラスのインスタンス
$expect = '.....'
$this->assertEquals($expect, $actual);
}
}
プライベートなプロパティは下記記事を参考にしてください。
【PHP】リフレクションクラスでprivate変数、privateメソッドをテストする|リスティング広告の運用代行ならカルテットコミュニケーションズ
PHPUnitの設定
preference > Languages & Frameworks > PHP > Test FrameWorks
ただしく設定するとツールバーからテストを実行できます。 Run テストクラス width Coverage を実行すると下記のようにカバレッジが表示できます。
setUp()
より前にdataProviderは実行されます。