CodeIgniter3でのテスト

CodeIgniter3でのテストについて、資料を作りましたので公開します。

(2020-03-29 追記) 見やすいようにマインドマップを更新し、マップの内容を本文に追記しました。

プレゼン資料

CodeIgniterのアーキテクチャ

CodeIgniterインスタンス

  • get_instance() で取得できるヤツ
  • 神オブジェクト的なシングルトンぽいもの
  • 実体はControllerのインスタンス
    • 想定
    • 1つのリクエストで1つしか生成されない

CI_Loaderクラス

  • モデル、ライブラリなどをロードするもの
  • 生成されたインスタンスをCodeIgniterインスタンスのプロパティに動的に追加する
    • CodeIgniterインスタンスが神オブジェクト化する
    • $this->foo がコントローラ、モデルで同じように使える
  • 関数にも依存している
    • load_class()
    • is_loaded()

CodeIgniter3のテスト上の問題点

グローバル状態

  • シングルトン
    • グローバル変数
  • 関数内のスタティック変数

exit() での終了

クラス名の衝突

  • 複数のコントローラに全く同じクラス名を付けられる

隠れた依存

ci-phpunit-test

ci-phpunit-testとは?

  • CodeIgniter3とPHPUnitをつなぐブリッジツール
  • 基本はPHPUnit
  • CodeIgniter本体のコードの書き換えは一切不要

アーキテクチャ

  • グローバル状態のリセット
    • CodeIgniterインスタンスのリセット
  • 構成
    • オートローダ
    • CodeIgniterのファイルの動的な置き換え
      • テスト上の問題点を解消する
    • $this->request によるControllerの機能テスト
    • ヘルパークラスやメソッド
      • テストコードを書きやすくするためのもの
      • ヘルパークラス
        • ReflectionHelper
      • ヘルパーメソッド
        • $this->getDouble()
    • Monkey Patch
      • ライブラリとして実装されている
      • 自転車の補助輪のようなもの
      • 最後の手段

テスト作成上のテクニック

resetInstance()

  • 何をするか?
    1. CodeIgniterインスタンスをリセットする
    2. 新しいCodeIgniterインスタンスを生成する
    3. $this->CI にCodeIgniterインスタンスを代入する
  • 呼び出し不要
    • newController()/newLibrary()/newModel() を使う場合
    • $this->request を使う場合

依存オブジェクトの注入

  • CI_Loaderにより作成されたプロパティはすべて動的なプロパティ
    • つまりpublic
      • インスタンス化後には外から注入可能
  • Controllerのテストの場合
    • setCallable()/addCallable() でプロパティにモックを注入すればよい

サンプルテストコード

さらに学習するには?

Tags: codeigniter, testing, phpunit

JavaScriptのDateオブジェクトとタイムゾーン

コンストラクタでの日付文字列の扱い

以下、Mac OSのブラウザで検証。

Firefox

JST
d = new Date('2017/09/01')

Date 2017-08-31T15:00:00.000Z

d = new Date('2017-09-01')

Date 2017-09-01T00:00:00.000Z

PDT
d = new Date('2017/09/01')

Date 2017-09-01T07:00:00.000Z

d = new Date('2017-09-01')

Date 2017-09-01T00:00:00.000Z

Chrome

JST

d = new Date('2017/09/01')

Fri Sep 01 2017 00:00:00 GMT+0900 (JST)

d = new Date('2017-09-01')

Fri Sep 01 2017 09:00:00 GMT+0900 (JST)

PDT

d = new Date('2017/09/01')

Fri Sep 01 2017 00:00:00 GMT-0700 (PDT)

d = new Date('2017-09-01')

Thu Aug 31 2017 17:00:00 GMT-0700 (PDT)

Safari

JST

> d = new Date('2017/09/01')

< Fri Sep 01 2017 00:00:00 GMT+0900 (JST)

> d = new Date('2017-09-01')

< Fri Sep 01 2017 09:00:00 GMT+0900 (JST)

PDT

> d = new Date('2017/09/01')

< Fri Sep 01 2017 00:00:00 GMT-0700 (PDT)

> d = new Date('2017-09-01')

< Thu Aug 31 2017 17:00:00 GMT-0700 (PDT)

まとめ

Firefox、Chrome、Safariとも

  • new Date('YYYY/MM/DD') だとローカルタイム
  • new Date('YYYY-MM-DD') だとUTC

と解釈される。

参考

Tags: javascript

PHPのプロジェクトではテストのカバレッジはどれくらいを目標にすべきなのか?

(最終更新:2017-09-11)

PHPUnitなどを使いアプリのテストを書いているプログラマーのみなさんはコードカバレッジも計測していることと思います。

ここで、カバレッジの目標としてはどれくらいがいいでしょうか?

以前、名古屋のPHPの勉強会でカバレッジの目標を定めているか?という質問を参加者にした時、目標を定めている人はいませんでした。

最近はPHPやCodeIgniterユーザでもテストを書いていない人は減ってきていますので、カバレッジについても興味を持っている人も増えていると思います。

私のアプリのカバレッジの目標

私の結論としては、一般論として、PHPのWebアプリのカバレッジ(PHPUnitでのラインカバレッジ)の目標は80%です。

それくらいあると、何かAPIを変えてしまったりして一部が動作しなくなっても、だいたいテストで検出されます。もちろん漏れることもありますが。

CodeIgniterのフォーラムでLonnieも80%がマジックナンバーだと言ってました。100%に近づくにつれてテスト作成のコストがより上がっていくため、安心感とコストのバランスから80%くらいがよいという経験的な話です。

また、周りを見ると、100%が基準とか、100%にこだわろうとかも見聞きしますが、実際問題いきなり100%は無理ゲーです。身の丈にあった目標でなくては、意味がありません。

テストファーストで普通に書いていけば、80%くらいは普通に達成できます。

少し検索すると、以下のような記述がありました。

カバレッジよりも大切なこと

それから、より重要なのはカバレッジレポートでテストされていないところに注目することです。テストしていないコードはリスクが高くなりますので、本当にテストしなくてよいか?を絶えず確認する必要があります。

ライブラリやフレームワークなどの場合

ちなみに、ライブラリやフレームワークという共通基盤の場合は、通常のWebアプリよりも高いカバレッジが要求されると思っています。90%とか100%近くとかですね。

CodeIgniterでのテストの書き方

CodeIgniterでテストの書き方がわからないという人には、以下の書籍をお薦めします(宣伝)。

関連

Tags: testing, php, phpunit, codeigniter