ci-phpunit-testのモンキーパッチ機能でexitを例外に変換したときのデバッグ方法
例えば、テスト中にちょっとデバッグしたいときに、以下のように変数をvar_dump()
して確認したいとします。
--- a/application/controllers/api/Example.php
+++ b/application/controllers/api/Example.php
@@ -40,7 +40,7 @@ class Example extends REST_Controller {
];
$id = $this->get('id');
-
+var_dump($id); exit;
// If the id parameter doesn't exist return all the users
if ($id === NULL)
通常はexit
でphpunitが終了し、以下のようになり楽に確認できます。
$ ../../vendor/bin/phpunit controllers/Uri_test.php
PHPUnit 4.7.7 by Sebastian Bergmann and contributors.
......string(1) "1"
ところが、モンキーパッチでexit
を例外に変換してしまっていると、
$ ../../vendor/bin/phpunit controllers/Uri_test.php
PHPUnit 4.7.7 by Sebastian Bergmann and contributors.
......EE
Time: 7.93 seconds, Memory: 17.75Mb
There were 2 errors:
1) Uri_test::test_api_example_users_uri
CIPHPUnitTestExitException: exit() called in Example::users_get()
/Users/kenji/work/codeigniter/ci-app-for-ci-phpunit-test/application/controllers/api/Example.php:43
/Users/kenji/work/codeigniter/ci-app-for-ci-phpunit-test/application/libraries/REST_Controller.php:654
/Users/kenji/work/codeigniter/ci-app-for-ci-phpunit-test/vendor/kenjis/ci-phpunit-test/application/tests/_ci_phpunit_test/CIPHPUnitTestRequest.php:312
/Users/kenji/work/codeigniter/ci-app-for-ci-phpunit-test/vendor/kenjis/ci-phpunit-test/application/tests/_ci_phpunit_test/CIPHPUnitTestRequest.php:256
/Users/kenji/work/codeigniter/ci-app-for-ci-phpunit-test/vendor/kenjis/ci-phpunit-test/application/tests/_ci_phpunit_test/CIPHPUnitTestRequest.php:133
/Users/kenji/work/codeigniter/ci-app-for-ci-phpunit-test/vendor/kenjis/ci-phpunit-test/application/tests/_ci_phpunit_test/CIPHPUnitTestCase.php:106
/Users/kenji/work/codeigniter/ci-app-for-ci-phpunit-test/application/tests/controllers/Uri_test.php:43
/Users/kenji/work/codeigniter/ci-app-for-ci-phpunit-test/vendor/phpunit/phpunit/phpunit:36
2) Uri_test::test_api_example_users_ruri
CIPHPUnitTestExitException: exit() called in Example::users_get()
/Users/kenji/work/codeigniter/ci-app-for-ci-phpunit-test/application/controllers/api/Example.php:43
/Users/kenji/work/codeigniter/ci-app-for-ci-phpunit-test/application/libraries/REST_Controller.php:654
/Users/kenji/work/codeigniter/ci-app-for-ci-phpunit-test/vendor/kenjis/ci-phpunit-test/application/tests/_ci_phpunit_test/CIPHPUnitTestRequest.php:312
/Users/kenji/work/codeigniter/ci-app-for-ci-phpunit-test/vendor/kenjis/ci-phpunit-test/application/tests/_ci_phpunit_test/CIPHPUnitTestRequest.php:256
/Users/kenji/work/codeigniter/ci-app-for-ci-phpunit-test/vendor/kenjis/ci-phpunit-test/application/tests/_ci_phpunit_test/CIPHPUnitTestRequest.php:133
/Users/kenji/work/codeigniter/ci-app-for-ci-phpunit-test/vendor/kenjis/ci-phpunit-test/application/tests/_ci_phpunit_test/CIPHPUnitTestCase.php:106
/Users/kenji/work/codeigniter/ci-app-for-ci-phpunit-test/application/tests/controllers/Uri_test.php:49
/Users/kenji/work/codeigniter/ci-app-for-ci-phpunit-test/vendor/phpunit/phpunit/phpunit:36
FAILURES!
Tests: 8, Assertions: 6, Errors: 2.
Generating code coverage report in Clover XML format ... done
Generating code coverage report in HTML format ... done
とこんな感じでexit
で終了してくれず、変数の値をうまく確認できません。
これは、ちょっと不便です。
そこで、今日は、PsySHを導入してデバッグを楽にします。
PsySHのインストール
require-dev
にpsy/psysh
を追加してcomposer update
します。
--- a/composer.json
+++ b/composer.json
@@ -9,6 +9,7 @@
"mikey179/vfsStream": "1.1.*",
"kenjis/ci-phpunit-test": "1.0.x@dev",
"satooshi/php-coveralls": "0.6.*",
- "phpunit/phpunit": "4.7.*"
+ "phpunit/phpunit": "4.7.*",
+ "psy/psysh": "0.5.*"
}
}
PsySHの動作には、最新のci-phpunit-test(2015/09/05以降の1.0.x@devまたはv0.7.0以降)が必要です。
デバッグの実際
デバッグのためにexit
を記載していた箇所(ブレークポイント)に、代わりにeval(\Psy\sh());
を記載します。
--- a/application/controllers/api/Example.php
+++ b/application/controllers/api/Example.php
@@ -40,7 +40,7 @@ class Example extends REST_Controller {
];
$id = $this->get('id');
-
+eval(\Psy\sh());
// If the id parameter doesn't exist return all the users
if ($id === NULL)
そして、phpunitを実行します。
$ ../../vendor/bin/phpunit controllers/Uri_test.php
PHPUnit 4.7.7 by Sebastian Bergmann and contributors.
......Psy Shell v0.5.2 (PHP 5.5.26 — cli) by Justin Hileman
ブレークポイントで止まり、PsySHが起動されました。
ここで、調べたい変数を入力すれば、値が表示されます。
$id
=> "1"
$users
=> [
[
"id" => 1,
"name" => "John",
"email" => "john@example.com",
"fact" => "Loves coding",
],
[
"id" => 2,
"name" => "Jim",
"email" => "jim@example.com",
"fact" => "Developed on CodeIgniter",
],
[
"id" => 3,
"name" => "Jane",
"email" => "jane@example.com",
"fact" => "Lives in the USA",
0 => [
"hobbies" => [
"guitar",
"cycling",
],
],
],
]
変数の一覧も取得できます。
>>> ls
Variables: $__ret__, $id, $this, $users
$__ret__
はモンキーパッチ機能が使っている特別な変数です。
関数を実行することもできます。
>>> get_class($this)
=> "Example"
オブジェクトのパブリックなプロパティの一覧。
>>> ls -p $this
Class Properties: $auth_override, $benchmark, $config, $form_validation, $format, $hooks, $input, $lang, $load, $loader, $output, $router, $security, $session, $uri
オブジェクトのすべてのプロパティの一覧。
>>> ls -p -a $this
Class Properties: $_allow, $_apiuser, $_args, $_delete_args, $_enable_xss, $_end_rtime, $_get_args, $_head_args, $_insert_id, $_options_args, $_patch_args, $_post_args, $_put_args, $_query_args, $_start_rtime, $_supported_formats, $_user_ldap_dn, $allowed_http_methods, $auth_override, $benchmark, $config, $form_validation, $format, $hooks, $http_status_codes, $input, $lang, $load, $loader, $methods, $output, $request, $response, $rest, $rest_format, $router, $security, $session, $uri
オブジェクトのパブリックなメソッドの一覧。
>>> ls -m $this
Class Methods: __construct, __destruct, _remap, delete, get, get_instance, head, options, patch, post, put, query, response, set_response, users_delete, users_get, users_post, validation_errors
バックトレース。
>>> trace
0: eval() at /Users/kenji/work/codeigniter/ci-app-for-ci-phpunit-test/application/controllers/api/Example.php:43
1: Example->users_get() at n/a:n/a
2: call_user_func_array() at /Users/kenji/work/codeigniter/ci-app-for-ci-phpunit-test/application/libraries/REST_Controller.php:654
3: REST_Controller->_remap() at n/a:n/a
4: call_user_func_array() at /Users/kenji/work/codeigniter/ci-app-for-ci-phpunit-test/vendor/kenjis/ci-phpunit-test/application/tests/_ci_phpunit_test/CIPHPUnitTestRequest.php:312
5: CIPHPUnitTestRequest->createAndCallController() at /Users/kenji/work/codeigniter/ci-app-for-ci-phpunit-test/vendor/kenjis/ci-phpunit-test/application/tests/_ci_phpunit_test/CIPHPUnitTestRequest.php:256
6: CIPHPUnitTestRequest->requestUri() at /Users/kenji/work/codeigniter/ci-app-for-ci-phpunit-test/vendor/kenjis/ci-phpunit-test/application/tests/_ci_phpunit_test/CIPHPUnitTestRequest.php:133
7: CIPHPUnitTestRequest->request() at /Users/kenji/work/codeigniter/ci-app-for-ci-phpunit-test/vendor/kenjis/ci-phpunit-test/application/tests/_ci_phpunit_test/CIPHPUnitTestCase.php:106
8: CIPHPUnitTestCase->request() at /Users/kenji/work/codeigniter/ci-app-for-ci-phpunit-test/application/tests/controllers/Uri_test.php:43
9: Uri_test->test_api_example_users_uri() at n/a:n/a
10: ReflectionMethod->invokeArgs() at /Users/kenji/work/codeigniter/ci-app-for-ci-phpunit-test/vendor/phpunit/phpunit/src/Framework/TestCase.php:881
11: PHPUnit_Framework_TestCase->runTest() at /Users/kenji/work/codeigniter/ci-app-for-ci-phpunit-test/vendor/phpunit/phpunit/src/Framework/TestCase.php:746
12: PHPUnit_Framework_TestCase->runBare() at /Users/kenji/work/codeigniter/ci-app-for-ci-phpunit-test/vendor/phpunit/phpunit/src/Framework/TestResult.php:601
13: PHPUnit_Framework_TestResult->run() at /Users/kenji/work/codeigniter/ci-app-for-ci-phpunit-test/vendor/phpunit/phpunit/src/Framework/TestCase.php:702
14: PHPUnit_Framework_TestCase->run() at /Users/kenji/work/codeigniter/ci-app-for-ci-phpunit-test/vendor/phpunit/phpunit/src/Framework/TestSuite.php:738
15: PHPUnit_Framework_TestSuite->run() at /Users/kenji/work/codeigniter/ci-app-for-ci-phpunit-test/vendor/phpunit/phpunit/src/TextUI/TestRunner.php:428
16: PHPUnit_TextUI_TestRunner->doRun() at /Users/kenji/work/codeigniter/ci-app-for-ci-phpunit-test/vendor/phpunit/phpunit/src/TextUI/Command.php:147
17: PHPUnit_TextUI_Command->run() at /Users/kenji/work/codeigniter/ci-app-for-ci-phpunit-test/vendor/phpunit/phpunit/src/TextUI/Command.php:99
18: PHPUnit_TextUI_Command::main() at /Users/kenji/work/codeigniter/ci-app-for-ci-phpunit-test/vendor/phpunit/phpunit/phpunit:36
オブジェクトのPHPDoc。
>>> doc $this
class Example extends REST_Controller
Description:
This is an example of a few basic user interaction methods you could use
all done with a hardcoded array
Package: CodeIgniter
Subpackage: Rest Server
Category: Controller
Author: Phil Sturgeon, Chris Kacerguis
License: MIT
Link: https://github.com/chriskacerguis/codeigniter-restserver
オブジェクトなどのソースコード。
>>> show $this::users_get
> 33| public function users_get()
34| {
35| // Users from a data store e.g. database
36| $users = [
37| ['id' => 1, 'name' => 'John', 'email' => 'john@example.com', 'fact' => 'Loves coding'],
38| ['id' => 2, 'name' => 'Jim', 'email' => 'jim@example.com', 'fact' => 'Developed on CodeIgniter'],
39| ['id' => 3, 'name' => 'Jane', 'email' => 'jane@example.com', 'fact' => 'Lives in the USA', ['hobbies' => ['guitar', 'cycling']]],
40| ];
41|
42| $id = $this->get('id');
43| eval(\Psy\sh());
44| // If the id parameter doesn't exist return all the users
45|
46| if ($id === NULL)
47| {
48| // Check if the users data store contains users (in case the database result returns NULL)
49| if ($users)
50| {
51| // Set the response and exit
52| $this->response($users, REST_Controller::HTTP_OK); // OK (200) being the HTTP response code
53| }
54| else
55| {
56| // Set the response and exit
57| $this->response([
58| 'status' => FALSE,
59| 'error' => 'No users were found'
60| ], REST_Controller::HTTP_NOT_FOUND); // NOT_FOUND (404) being the HTTP response code
61| }
62| }
63|
64| // Find and return a single record for a particular user.
65|
66| $id = (int) $id;
67|
68| // Validate the id.
69| if ($id <= 0)
70| {
71| // Invalid id, set the response and exit.
72| $this->response(NULL, REST_Controller::HTTP_BAD_REQUEST); // BAD_REQUEST (400) being the HTTP response code
73| }
74|
75| // Get the user from the array, using the id as key for retreival.
76| // Usually a model is to be used for this.
77|
78| $user = NULL;
79|
80| if (!empty($users))
81| {
82| foreach ($users as $key => $value)
83| {
84| if (isset($value['id']) && $value['id'] === $id)
85| {
86| $user = $value;
87| }
88| }
89| }
90|
91| if (!empty($user))
92| {
93| $this->set_response($user, REST_Controller::HTTP_OK); // OK (200) being the HTTP response code
94| }
95| else
96| {
97| $this->set_response([
98| 'status' => FALSE,
99| 'error' => 'User could not be found'
100| ], REST_Controller::HTTP_NOT_FOUND); // NOT_FOUND (404) being the HTTP response code
101| }
102| }
コマンドがわからないときはヘルプを表示しましょう。
>>> help
help Show a list of commands. Type `help [foo]` for information about [foo]. Aliases: ?
ls List local, instance or class variables, methods and constants. Aliases: list, dir
dump Dump an object or primitive.
doc Read the documentation for an object, class, constant, method or property. Aliases: rtfm, man
show Show the code for an object, class, constant, method or property.
wtf Show the backtrace of the most recent exception. Aliases: last-exception, wtf?
whereami Show where you are in the code.
throw-up Throw an exception out of the Psy Shell.
trace Show the current call stack.
buffer Show (or clear) the contents of the code input buffer. Aliases: buf
clear Clear the Psy Shell screen.
history Show the Psy Shell history. Aliases: hist
exit End the current session and return to caller. Aliases: quit, q
確認が済んだら、[control]+[c]キーでphpunitを終了させましょう。
^C
という感じで、コマンドラインが好きな人にはPsySHをお薦めします。
関連
- CI PHPUnit Test
- CodeIgniter 3.0でPHPUnitを使う
- イマドキのCodeIgniterでPHPUnit入門 - Qiita
- イマドキのCodeIgniterでPHPUnit入門(Composer不使用編) - Qiita
- CodeIgniterとPHPUnitでテストが難しいコードを簡単にテストする(オブジェクトメソッドの置換)
- ci-phpunit-testを使って和田卓人さんの『現在時刻に依存するテスト』を書いてみる
- ci-phpunit-testでsingletonなクラスを呼び出してるメソッドをテストする - Qiita
- ci-phpunit-test v0.4.0をリリースしました
Date: 2015/09/04