9.テストの組み込み¶
9.1.戻り値の返却¶
次は戻り値を返す関数のサンプルとして、my_add_return_int() をやってみましょう。my_lib.h における C のプロトタイプ宣言は以下の通りです。
~/my_lib$ grep my_add_return_int my_lib.h
extern int my_add_return_int(int a, int b);
関数の実体は以下の通りです。
~/my_lib$ cat components/my_add_return_int.c
#include <stdio.h>
int my_add_return_int(int a, int b)
{
return a + b;
}
これに対応する、PHP レベルの仕様は以下のようになります。
-
int my_add_return_int( int $a, int $b )
-
$a と $b の和を返します。
実装は以下のようになりました。
~/php/ext/my_ext$ git diff my_ext.c
diff --git a/my_ext.c b/my_ext.c
index e0cec50..2581718 100644
--- a/my_ext.c
+++ b/my_ext.c
@@ -90,6 +90,23 @@ PHP_FUNCTION(my_echo_int)
}
/* }}} */
+/* {{{ proto int my_add_return_int( int a, int b )
+ a と b の和を返します。
+*/
+PHP_FUNCTION(my_add_return_int)
+{
+ zend_long a, b;
+
+ if (ZEND_NUM_ARGS() < 2 || 2 < ZEND_NUM_ARGS()) {
+ WRONG_PARAM_COUNT;
+ }
+ if (zend_parse_parameters(ZEND_NUM_ARGS(), "ll", &a, &b) == FAILURE) {
+ return;
+ }
+ RETURN_LONG(my_add_return_int(a, b));
+}
+/* }}} */
+
/* {{{ php_my_ext_init_globals
*/
/* Uncomment this function if you have INI entries
@@ -165,6 +182,7 @@ PHP_MINFO_FUNCTION(my_ext)
const zend_function_entry my_ext_functions[] = {
PHP_FE(confirm_my_ext_compiled, NULL) /* For testing, remove l
PHP_FE(my_echo_int, NULL)
+ PHP_FE(my_add_return_int, NULL)
PHP_FE_END /* Must be the last line in my_ext_functions[] */
};
/* }}} */
ビルドして実行してみました。うまくいっているようです。
~/php/ext/my_ext$ php -r "print my_add_return_int(3,4).PHP_EOL;"
7
9.2.PHPUnitの導入¶
いくつかパラメーターのパターンを追加してみましょう。毎回コマンドラインからテストパターンを入力するのは効率が悪いので、 PHPUnit によるユニットテストを行います。PHPUnit は、以下の手順で導入します。
~$ wget https://phar.phpunit.de/phpunit-6.2.phar
~$ chmod +x phpunit-6.2.phar
~$ sudo mv phpunit-6.2.phar /usr/local/bin/phpunit
~$ phpunit --version
PHPUnit 6.2.1 by Sebastian Bergmann and contributors.
9.3.最初のテストケース¶
コマンドラインから行った動作確認を、PHPUnit 経由で実行します。tests 配下に以下の PHP スクリプトを置きます。
~$ cd ~/php/ext/my_ext
~/php/ext/my_ext$ vi tests/MyAddReturnIntTest.php
~/php/ext/my_ext$ cat tests/MyAddReturnIntTest.php
<?php
use PHPUnit\Framework\TestCase;
class MyAddReturnIntTest extends TestCase
{
public function test3plus4returns7()
{
$ret = my_add_return_int(3, 4);
$this->assertEquals(7, $ret);
}
}
それでは実行してみます。
~/php/ext/my_ext$ phpunit tests/MyAddReturnIntTest.php
PHPUnit 6.2.1 by Sebastian Bergmann and contributors.
. 1 / 1 (100%)
Time: 120 ms, Memory: 10.00MB
OK (1 test, 1 assertion)
7
と返ってきた加算結果 $ret
を比較したら等しかったので、テストは成功です。 assertEquals()
は PHPUnit のアサーションのひとつです。詳細は 付録A アサーション - assertEquals() を参照してください。
9.4.テストケースの追加¶
MyAddReturnIntTest クラスの中に、以下のようなパラメーターが1個しかないケースを追加しました。
~/php/ext/my_ext$ git diff
diff --git a/tests/MyAddReturnIntTest.php b/tests/MyAddReturnIntTest.php
index e27db50..9210507 100644
--- a/tests/MyAddReturnIntTest.php
+++ b/tests/MyAddReturnIntTest.php
@@ -9,4 +9,9 @@ class MyAddReturnIntTest extends TestCase
$ret = my_add_return_int(3, 4);
$this->assertEquals(7, $ret);
}
+
+ public function testLackOfParameter()
+ {
+ $ret = my_add_return_int(3);
+ }
}
これで実行してみますと、
~/php/ext/my_ext$ phpunit tests/MyAddReturnIntTest.php
PHPUnit 6.2.1 by Sebastian Bergmann and contributors.
.E 2 / 2 (100%)
Time: 121 ms, Memory: 10.00MB
There was 1 error:
1) MyAddReturnIntTest::testLackOfParameter
Wrong parameter count for my_add_return_int()
/usr/local/src/php-7.1.5/ext/my_ext/tests/MyAddReturnIntTest.php:15
ERRORS!
Tests: 2, Assertions: 1, Errors: 1.
エラーになってしまいました。
9.5.エラーと例外の扱い¶
PHP におけるエラーと例外は、 Standard PHP Library (SPL) で規定されています。ソースツリーの中の実体は、php/ext/spl/spl.php にあります。
PHPUnit でもエラーと例外は 標準でサポート されているのですが、手元で試した限りでは、引数誤りエラーを補足することはできませんでした。試した結果、以下の方法でうまくいくようになりました。
まず、テスト前処理を行なうクラス setUpBeforeClass() を定義し、その中でエラーを捕捉して RuntimeException 例外を発生させるようにします。 setUpBeforeClass()
などは フィクスチャ と呼ばれるもので、マニュアルに詳細に記載があります。
~/php/ext/my_ext$ cat tests/MyTestCase.php
<?php
use PHPUnit\Framework\TestCase;
class MyTestCase extends TestCase
{
public static function setUpBeforeClass() {
set_error_handler(function($errno, $errstr, $errfile, $errline) {
throw new RuntimeException($errstr . " on line "
. $errline . " in file " . $errfile);
});
ini_set('log_errors', 1);
ini_set('display_errors', 0);
}
}
そして、実際のテストケースは、新たに作成した MyTestCase を継承するようにします。また、関数コールに対して RuntimeException 例外の発生を期待することを PHPunit に教えます。コメントの中で '@' 記号で指示するメタデータは アノテーション と呼ばれます。
$ git diff
diff --git a/tests/MyAddReturnIntTest.php b/tests/MyAddReturnIntTest.php
index 243bf88..dd28dce 100644
--- a/tests/MyAddReturnIntTest.php
+++ b/tests/MyAddReturnIntTest.php
@@ -1,8 +1,8 @@
<?php
-use PHPUnit\Framework\TestCase;
+require_once 'MyTestCase.php';
-class MyAddReturnIntTest extends TestCase
+class MyAddReturnIntTest extends MyTestCase
{
public function test3plus4returns7()
{
@@ -10,6 +10,9 @@ class MyAddReturnIntTest extends TestCase
$this->assertEquals(7, $ret);
}
+ /**
+ * @expectedException RuntimeException
+ */
public function testLackOfParameter()
{
my_add_return_int(3);
これで一応通るようになりました。
~/php/ext/my_ext$ phpunit tests/MyAddReturnIntTest.php
PHPUnit 6.2.1 by Sebastian Bergmann and contributors.
.. 2 / 2 (100%)
Time: 138 ms, Memory: 10.00MB
OK (2 tests, 2 assertions)
ただ、なんだかやっつけのような気もするので、本来のやり方(?)がわかったら追記します。