「それより俺のテストを見てくれ。こいつをどう思う?」「すごく・・・日本語です・・・・」
「それより俺のテストを見てくれ。こいつをどう思う?」
「すごく・・・日本語です・・・・」
オラっち、日本語でテストメソッド名を定義するんダーーイ
PHPって、メソッド名を日本語で定義できます(文字コードUTF-8なら)。PHPでTDDワークショップで初めて知りました。
ということでテストクラスのメソッドを日本語で定義してたんですが、普通はメソッド名が日本語になってたら驚きますよね。
ということで、日本語でメソッドを定義することについて、ちょっとまとめてみます。
日本語で関数定義とかマジ勘弁☆
日本語メソッド名に対する拒否反応はおおよそ以下のような感じ。
とにかくありえない
- ありえん
- なにこれキモい
- (無言で)rm -rf test/unit/*
気持ちはわかります。具体的には次のどちらか、もしくは両方になるんじゃないでしょうか。
ひらがなと漢字がありえない
- 日本語ネイティブでない人が関わる可能性がある(可能性を無視できない)
確かにこの場合日本語はナシでしょう。(こういうケースが多いと思いますが)
ドキュメントとしてのテストコードの存在意義が潰されてしまいますからね。
自然文がありえない
- たとえ英語でであっても "testHogeShouldBeConvertedToFugaWheneverFlagIsTrue()" みたいなのはメソッド名として受け入れられない。
あいやしばらく!
こういうケースでは "testHogeParser()"みたいなテストメソッドの中に大量のassersionが詰め込まれて、そのテストメソッドが何をテストしたいのかわかりづらくなっている場合があり、日本語にするかどうかは別としても一考の余地ありだと思っています。
でもちょっと待って、そのテストメソッドはなんのため?
テストメソッドって(別のコードから)呼び出さないよね
このメソッドを呼び出すために日本語をカタカタ打ち込んだりする必要はないです。
後から読むだけであり、あとから読むことが重要です。
通常のメソッドと違ってコードの文脈の中で目にすることはなく、見るのは定義本体のみで、通常のメソッド名に求められるような「簡潔さ」は求められません。
詳細に保証(説明)したいことがある
テストメソッドは1つの事柄をテストすべきで、メソッド名はテストで保証(説明)したい事柄を明確にするものであるべきです。
これは1つのテストメソッドにassertionを1つだけとするのが良いとされる理由の一つです。
「そのメソッドが何をテストしているのか」が重要になります。
仕様書を見るのに近い感覚で後から見ることが多い
テスト対象の仕様やインターフェースを保証するドキュメント的な役割を求めてテストケースを見ることがあります。
アウトラインからテストメソッド一覧を俯瞰する等の場合、一目で内容が頭に入ると嬉しいです。
じゃぁ日本語で書いたらよくね?
上に挙げたような理由で、テストが日本語(英語にしても自然文に近い形)で書いてあると得すると考えています。
表現しやすい&伝わりやすい
ドキュメントやWikiを日本語で書く感覚でテストメソッドを日本語で書いています。
対象処理の仕様や気を付けたい罠動作を他者に伝えたいとき、テストが意図することを表現しやすいです。
一覧時の一目で分かる感
テストメソッド一覧を出したり、テストの失敗レポートが出た時などにその効果を感じます。
*ただし
「環境が許せば」です。日本語ネイティブ以外の人が触れる可能性を無視できないなら日本語にするのは難しいでしょうし、「生理的に受け付けない」というのも無視できない理由になり得ます。
ものにもよります。「Githubで公開」的なものは全部英語でやったほうが得が多いでしょう。
まとめ
つまり日本語がどうどいうよりは
- テストの粒度を小さく保とう
- テストが何をテストしているのか明確にしよう
追記 2012/04/26
メソッド名に日本語を使うとエディタによってはシンタックスハイライトが正しく動作しないケースがあることが判明。(なにをいまさら)
英語派に寝返る。
自分用にインストールしたpearを使おうとしてredeclareみたいに文句言われた場合
丁度ファイル入出力が絡むテストを書いて、めんどくさいなー、と思っていたところに
http://blog.yuyat.jp/archives/1280
↑でvfsStreamというものが紹介されていたので試そうとしたらひっかかったのでメモ。
とりあえずCache_Casualのテストを実行してみる
tests/unit/bootstrap.phpに自分用pearのインクルードパスを追加。
<?php set_include_path('/home/calpo/share/pear/php' . PATH_SEPARATOR . get_include_path());
$ phpunit --bootstrap bootstrap.php Cache/Casual/Container/FileTest.php PHP Fatal error: Cannot redeclare class File_Iterator in /home/calpo/share/pear/php/File/Iterator.php on line 196 Fatal error: Cannot redeclare class File_Iterator in /home/calpo/share/pear/php/File/Iterator.php on line 196
自分用のpearディレクトリは後ろに設定する
<?php // × set_include_path('/home/calpo/share/pear/php' . PATH_SEPARATOR . get_include_path()); // ○ set_include_path(get_include_path() . PATH_SEPARATOR . '/home/calpo/share/pear/php');
実行できるようになった。
$ phpunit --bootstrap bootstrap.php Cache/Casual/Container/FileTest.php PHPUnit 3.5.3 by Sebastian Bergmann. .. Time: 0 seconds, Memory: 5.25Mb OK (2 tests, 2 assertions)
PyrusでプロジェクトローカルなPEARライブラリインストール : PHP Advent Calendar jp 2011 Day 10
PHP Avent Calendar jp 2011の10日目、[twitter:@calpo22]です。
→前日「includeとextractの組み合わせでテンプレート処理を作る。PHPのAdvent Calender #9 - それマグで!」
※追記 2012/09/16
PHPが古いとかの事情がなければ、今はライブラリの依存管理にはcomposer使うのがいいと思います。
取り急ぎ手元でPHPUnit使いたいとかであれば http://qiita.com/items/81085381c4281e498cde で一発。
みなさんPEAR使ってますか?
PEARのライブラリを普通にインストールすると/usr/binとかに入るんですが、そうじゃなくて自分用に~/binに入れたいとか、フレームワークのvendorディレクトリに入れたいとかありますよね。
これで結構苦労していたところ、今年のPHPカンファレンスで「Pyrus使うと捗るよ」みたいな話を聞きくことができました。
pearの後継となるパッケージマネージャらしく、「なにそれすごい!これでかつる!」と期待に胸をふくらませつつ家に帰って試してみたところ・・・
とにかく日本語の情報が全然無い
という状態でなんか凹みました。
でも、Pyrusだとpearよりもプロジェクトローカルなライブラリのインストールがやりやすいです!
ということでPyrusによるPEARライブラリインストールのご紹介。
まずは俺ローカルなPEARライブラリインストール
~/mypyrusに自分用のPEARライブラリをインストールしてみます。
(必ずしも俺ローカルが必要なわけではないですが、整理しやすかったのでこのようにしています)
pyrus.pharダウンロード
pyrus.phar自体はどこにあってもいいんですが、とりあえず~/mypyrusに入れておくことに。
$ mkdir mypyrus $ cd mypyrus/ $ wget http://pear2.php.net/pyrus.phar
pyrusの初期設定
最初にpyrusを実行すると初期設定が行われ、パッケージのインストール先のディレクトリ等が設定されます。
$ php pyrus.phar install Pyrus version 2.0.0a3 SHA-1: BE7EA9D171AE3873F1BBAF692EEE9165BB14BD5D Pyrus: No user configuration file detected It appears you have not used Pyrus before, welcome! Initialize install? Please choose: yes no [yes] : # ↑yesなのでそのままEnter Great. We will store your configuration in: /home/calpo/.pear/pearconfig.xml Where would you like to install packages by default? [/home/calpo/mypyrus] : # ↑にインストールなのでそのままEnter $ ls ~/.pear/pearconfig.xml /home/calpo/.pear/pearconfig.xml
~/.pear/pearconfig.xmlが作成されます。
config-showコマンドで設定を確認できます。
$ php pyrus.phar config-show Pyrus version 2.0.0a3 SHA-1: BE7EA9D171AE3873F1BBAF692EEE9165BB14BD5D Using PEAR installation found at /home/calpo/mypyrus System paths: php_dir => /home/calpo/mypyrus/php ext_dir => /usr/lib64/php/modules cfg_dir => /home/calpo/mypyrus/cfg doc_dir => /home/calpo/mypyrus/docs bin_dir => /usr/bin data_dir => /home/calpo/mypyrus/data ・ ・
bin_dirが/usr/binになっているので自分用に変更しましょう。
(~/mypyrus/.config が生成されます)
$ php pyrus.phar set bin_dir /home/calpo/mypyrus/bin $ php pyrus.phar config-show ・ ・ bin_dir => /home/calpo/mypyrus/bin ・ ・
PHPUnitインストール
準備ができたので俺専用PHPUnitをインストールしてみましょう。
$ php pyrus.phar set auto_discover on $ php pyrus.phar channel-discover pear.phpunit.de $ php pyrus.phar install phpunit/PHPUnit Pyrus version 2.0.0a3 SHA-1: BE7EA9D171AE3873F1BBAF692EEE9165BB14BD5D Using PEAR installation found at /home/calpo/mypyrus Sorry, phpunit/PHPUnit references an unknown channel pear.symfony-project.com for pear.symfony-project.com/YAML Do you want to add this channel and continue? Please choose: yes no [yes] : # ↑途中チャンネルの追加について問われます ・ ・ pear.phpunit.de/PHP_Invoker depended on by pear.phpunit.de/PHPUnit
どん!
入りました。
$cd ~/mypyrus $ ls bin cache docs downloads php pyrus.phar $ ls bin/ phpunit $ ls php/ File PHP PHPUnit SymfonyComponents Text
include_pathの設定
早速bin/に入ったphpunitを実行しようとしても、必要なディレクトリがinclude_pathに設定されていないので怒られます。
$ cd ~/mypyrus/bin $ ./phpunit Warning: require(PHPUnit/Autoload.php): failed to open stream: No such file or directory in /home/calpo/mypyrus/bin/phpunit on line 42 $ php -i | grep include_path include_path => .:/usr/share/pear:/usr/share/php => .:/usr/share/pear:/usr/share/php
今回はお手軽に~/mypyrus/bin/phpunit に設定を追加して、~/mypyrus/phpをinclude_pathに入れてしまいます。
<?php // ↓をrequireの前に追加 set_include_path( realpath(dirname(__FILE__).'/../php') . PATH_SEPARATOR . dirname(__FILE__) . PATH_SEPARATOR . get_include_path());
ただライブラリによってbin/に入るファイルがphpスクリプトだったりシェルスクリプトだったり、PHP_CLASSPATHみたいな独自の環境変数を設定する必要があったりとなんかもう・・・
php.iniが変更できるならそれが一番確実です。
$ cd ~/mypyrus/bin $ ./phpunit --version PHPUnit 3.6.4 by Sebastian Bergmann.
いぇーい
プロジェクトローカルなPEARライブラリインストール
続いて適当なプロジェクトのvendorディレクトリにプロジェクト専用PEARライブラリをインストールしてみます。
ディレクトリの設定
setとかのコマンドの前にディレクトリを指定してあげると、そこローカルな作業と設定ができます。
(そのディレクトリに.configが出来上がります)
例えば~/project_hoge/vendorにインストールする場合・・・
$ php pyrus.phar /home/calpo/project_hoge/vendor set bin_dir /home/calpo/project_hoge/vendor/bin $ php pyrus.phar /home/calpo/project_hoge/vendor config-show Pyrus version 2.0.0a3 SHA-1: BE7EA9D171AE3873F1BBAF692EEE9165BB14BD5D Using PEAR installation found at /home/calpo/project_hoge/vendor System paths: php_dir => /home/calpo/project_hoge/vendor/php ext_dir => /usr/lib64/php/modules cfg_dir => /home/calpo/project_hoge/vendor/cfg doc_dir => /home/calpo/project_hoge/vendor/docs bin_dir => /home/calpo/project_hoge/vendor/bin ・ ・
インストール
チャンネルの設定などもプロジェクトローカルなのでまた設定します。
$ php pyrus.phar /home/calpo/project_hoge/vendor set auto_discover on $ php pyrus.phar /home/calpo/project_hoge/vendor channel-discover pear.phpunit.de $ php pyrus.phar /home/calpo/project_hoge/vendor install phpunit/PHPUnit ・ ・ pear.phpunit.de/PHP_Invoker depended on by pear.phpunit.de/PHPUnit $ ls ~/project_hoge/vendor/bin phpunit
こんな感じでプロジェクトローカルなPEARライブラリをほいほいインストールしていけます。
session_set_save_handler()でカスタムセッションハンドラ設定したらFatal error: Class not found
複数のwebサーバーでセッション情報共有するのにmemcached使うためにカスタムセッションハンドラ設定したら
ばっちり定義してるはずのクラスがなかったことになっててびびった話。
問題のあったスクリプト
<?php class Hoge {} class MySessionHandler { public function open($save_path, $session_name){ /*処理*/ } public function close(){ /*処理*/ } public function read($id){ /*処理*/ } public function write($id, $sess_data){ $hoge = new Hoge(); } public function destroy($id){ /*処理*/ } public function gc($maxlifetime){ /*処理*/ } } $s = new MySessionHandler(); session_set_save_handler(array($s,'open'), array($s,'close'), array($s,'read'), array($s,'write'), array($s,'destroy'), array($s,'gc')); session_start(); $_SESSION['fuga'] = 'abc';
↓ごらんの有様だよ!
Fatal error: Class 'Hoge' not found in /xxx/xxx/sessiontest.php on line 8
Hogeってすぐそこに定義してるじゃん! Σ(・ω・;)
エラーの原因
どこでエラーになってるか
session_set_save_handler()の引数(callback $write)で指定した処理の実行時にエラーが起きています。
解決方法
デストラクタでsession_write_close()
オブジェクト破棄の前にwriteハンドラコールすればよい。
http://php.mirror.camelnetwork.com/manual/ja/function.session-set-save-handler.php#refsect1-function.session-set-save-handler-notes
この「ニワトリが先かタマゴが先か」の問題を解決するために、 デストラクタから session_write_close() を コールすることが可能です。
こんな感じでOK
<?php class MySessionHandler { // 省略 // // ↓追加 public function __destruct(){ session_write_close(); } }
SSLでエラー ssl_error_rx_record_too_long (-12263)
ブラウザにssl_error_rx_record_too_longと出力されて接続できない。
エラーログには↓のように出る。
[Mon Sep 19 22:46:23 2011] [error] [client xxx.xxx.xxx.xxx] Invalid method in request \x16\x03\x01
一般的な原因
設定は正しいのにSSL関連の設定部分を通らないケース
httpd.confに
<IfDefine SSL> ・ ・ </IfDefine>
と書いてあるのに"SSL"がDefineされていなかったというオチ。
おまけ)意図とは違うバーチャルホストの設定を見てしまう件
ネームベースのバーチャルホストを設定している場合に問題になります
SSL接続時は、ホスト名も暗号化されています。
なので、SSLの設定を読み込んでからでないとホスト名を特定できません。
でもネームベースのバーチャルホストの場合、ホスト名が分からないのでバーチャルホストの設定を読むことができません。
先頭のバーチャルホストの設定が使われます
このとき、とりあえずhttpd.confで最初に定義してあるバーチャルホストの設定が使われます。
(ホスト名が決まったらネームベースバーチャルホストの設定も有効になります)
つまり
目的のバーチャルホストの設定だけがんばってもだめで、先頭のバーチャルホストのSSL設定もちゃんとされている必要があります。
quickrun: Specified outputter is not registered: buffer
久しぶりに:BundleInstall!して、quickrun.vimがVersion0.5.0になったら動かなくなっちゃったけど、
vim scriptもgitもよく分かってなかったので前のバージョンを使うようにするのに苦労したからメモ。
[追記 20110906]
ちゃんと新しいvimを使ってればこんなことにはならないと考えます。
(コメント参照)
quickrunできなくなっちゃった
Vundleでquickrun.vim導入していました。
Bundle 'quickrun.vim'
ふと思い立って:BundleInstall!で更新したところquickrunでエラーが出るようになってしまいました。
/home/calpo/.vim/bundle/quickrun.vim/autoload/quickrun/outputter/browser.vim の処理中にエラーが検出されました: 行 27: E475: 無効な引数です: 77 quickrun: Specified outputter is not registered: buffer 続けるにはENTERを押すかコマンドを入力してください
古いバージョンにする
プラグインのディレクトリに移動して前のバージョンのコミットID確認
$ cd ~/.vim/bundle/quickrun.vim/ $ git log commit 7e440caa04fef77ab29c7bb9c954866c60399020 Author: thinca <thinca+vim@gmail.com> Date: Tue Jul 26 00:00:00 2011 +0000 Version 0.5.0 - Implemented the module system. - Some options are not compatible. - See :help quickrun-module more details. - Moved QuickRun() into quickrun#operator(). - Other many changes. commit 162ff2788fea8e2da9a3feea8db9ed6a89c63c45 Author: thinca <thinca+vim@gmail.com> Date: Mon May 23 00:00:00 2011 +0000 Version 0.4.7: - Added and improved the default values.
Version 0.4.7をチェックアウト
$ git checkout 162ff2788fea8e2da9a3feea8db9ed6a89c63c45
とりあえずこれで再びquickrunが使えるようになりました。
$ git branch -a * (no branch) master remotes/origin/HEAD -> origin/master remotes/origin/master
なんか間違ってる気もするけどとりあえずはこれでしのぐの・・・
root権のない一般ユーザーでも開発環境でCI(Jenkins/PHPUnit/Phing)してみたい (中編)
自分用pearの準備
pear自体はPHPについてくるので誰でもつかえると思うんですが、インストール先が/usr/local/phpとかだったり、そもそもpearが古かったりするので自分用のを入れましょう。
.pearrcの生成
/home/calpo/pear に自分用のpearを置くとすると、以下のようにします。
$ cd ~/ $ pear config-create /home/calpo/share .pearrc Configuration (channel pear.php.net): ===================================== Auto-discover new Channels auto_discover <not set> Default Channel default_channel pear.php.net HTTP Proxy Server Address http_proxy <not set> PEAR server [DEPRECATED] master_server <not set> Default Channel Mirror preferred_mirror <not set> Remote Configuration File remote_config <not set> PEAR executables directory bin_dir /home/calpo/share/pear PEAR documentation directory doc_dir /home/calpo/share/pear/docs PHP extension directory ext_dir /home/calpo/share/pear/ext PEAR directory php_dir /home/calpo/share/pear/php ・ ・
.pearrcには自分用pearの設定が保存され、↑で出力された内容は"pear config-show"でいつでも確認できます。
自分用pear本体のインストール
$ pear install -o PEAR WARNING: channel "pear.php.net" has updated its protocols, use "pear channel-update pear.php.net" to update downloading PEAR-1.9.4.tgz ... ・ ・ PEAR: To install optional features use "pear install pear/PEAR#featurename"
PHPUnitインストール
チャンネル追加してインストール
$ pear channel-discover pear.phpunit.de $ pear channel-discover components.ez.no $ pear channel-discover pear.symfony-project.com $ pear install phpunit/PHPUnit Did not download optional dependencies: ezc/ConsoleTools, use --alldeps to download automatically Failed to download pear/HTTP_Request2 within preferred state "stable", latest release is version 2.0.0RC1, stability "beta", use "channel://pear.php.net/HTTP_Request2-2.0.0RC1" to install phpunit/PHPUnit can optionally use PHP extension "dbus" pear/XML_RPC2 requires package "pear/HTTP_Request2" (version >= 0.6.0) phpunit/PHPUnit requires package "pear/XML_RPC2"
文句言われた
一個ずつ足りないものを入れようとするとさらに文句言われたりしたので最終的に↓のようにやった
$ pear install channel://pear.php.net/Net_URL2-0.3.1 $ pear install channel://pear.php.net/HTTP_Request2-2.0.0RC1 $ pear install pear/XML_RPC2 $ pear install phpunit/PHPUnit $ phpunit -v PHPUnit 3.5.3 by Sebastian Bergmann.
これでやっと入る
※curl関連でけちが付いた場合は → http://lazesoftware.com/blog/11/0213/
Phingインストール
pearでさっくり
$ pear channel-discover pear.phing.info $ pear install phing/phing $ phing -v PHP Warning: require_once(phing/Project.php): failed to open stream: No such file or directory in /home/calpo/share/pear/php/phing/Phing.php on line 22
インストールはWarningでつつも無事終わるが動かない。
PHPのinclude_pathが通ってないので通す
通常のpearインストールディレクトリは自動的にinclude_pathに含まれるようになってるんですが、今回は自分用なので自分でinclude_pathを設定する必要があります。
share/pear/php/phing.php の最初の方に↓を追加
<?php ini_set('include_path', ini_get('include_path').':'.dirname(__FILE__)); ・ ・
(本当はphp.iniに書いたりphpコマンド実行時に-dオプション指定したりしたいけど)
./phing -v Phing 2.4.6
完了。