社内最長老のシステムにPHPUnitで立ち向かう方法
by
penguin045
Link
Embed
Share
Beginning
This slide
Copy link URL
Copy link URL
Copy iframe embed code
Copy iframe embed code
Copy javascript embed code
Copy javascript embed code
Share
Tweet
Share
Tweet
Slide 1
Slide 1 text
社内最長老のシステムに PHPUnit で立ち向かう方法 やなせ たかし
Slide 2
Slide 2 text
自己紹介 やなせ たかし 株式会社ラクスで働いています。 PHP 歴 9 か月 Scala 大好きマン 2
Slide 3
Slide 3 text
今日話すこと 18 年稼働しているシステムの PHP をバージョンアップをしたときの戦い方 ● レガシーネタです。 ● 適用範囲は限定的です。 ● PHP8 完全対応!ではありません。 話さないこと ● レガシーシステムとの戦い方 ● 実装の話 3
Slide 4
Slide 4 text
背景 ● PHP 7.1 => 7.3 へのバージョンアップをすることになった ○ ちょうど今日 EOL ですね ● 調査までは PJ 横断だが、設計・実装担当は 1 人 ○ しかも PHP 歴 3 か月 ● 実装まではつつがなく終了 4
Slide 5
Slide 5 text
_人人人人人人人人人人人_ > 突然の全機能テスト <  ̄Y^Y^Y^Y^Y^Y^Y^Y^Y^Y ̄ 5
Slide 6
Slide 6 text
ルール 環境 ● 老舗サービス (18 年モノ ) ● ソースコードは当然レガシーなものが多い テストクリアの条件 ● 重要機能はカバレッジ 100% (C0) を取ること ● 非重要機能は全機能の動作確認が完了している 6
Slide 7
Slide 7 text
戦い方を考える 手札 ● 一部共通関数の PHPUnit ● 一部シナリオの Selenium テスト ● 正常系の回帰テスト ( 手動 ) 戦術 ● 既存テストは利用する ● 不足分を PHPUnit で担保する 7
Slide 8
Slide 8 text
トランザクションスクリプト対策 戦術:とにかくモックを使う ● これまで自動テストでモックを使ってこなかった ● 呼び出している関数を大胆にモック化 ● 呼び出し先はテスト済みなので、テストの責務外 8
Slide 9
Slide 9 text
uopz 拡張(User Operations for Zend) ● Zend エンジンの振舞いを操作する拡張 ● あらゆる関数をモック化するために使用 ● 引数にクロージャが渡せて、過去のデファクトだった runkit より使い勝手がいい ● トランザクションスクリプト内の関数を狙い撃ちしてモック化 しなければならないケースで活躍 9
Slide 10
Slide 10 text
テスト作成開始 10
Slide 11
Slide 11 text
甘すぎる見通し 11
Slide 12
Slide 12 text
トランザクションスクリプトには 12
Slide 13
Slide 13 text
勝てなかった 13
Slide 14
Slide 14 text
高すぎるカバレッジ取得の壁 14
Slide 15
Slide 15 text
どうやってもルール通りカバレッジは取れない ● 条件分岐に入るのが至難の業 ○ 放置されている謎のロジック ○ 巨大なトランザクションスクリプト ○ 変数の再代入・フラグの再利用が横行 ● グローバル変数の濫用 => テストするべきかどうかを精査したほうが早い 15
Slide 16
Slide 16 text
テストの取捨選択が必要 16
Slide 17
Slide 17 text
カバレッジ取得するもの ● 既存テストでカバーできるもの ● 重要機能にまつわる小さな関数・メソッド ○ 他の関数に依存していないもののみ ○ 依存が少なければモックなどでテストする 17
Slide 18
Slide 18 text
これらは問題ない 18
Slide 19
Slide 19 text
本丸に切り込む 19
Slide 20
Slide 20 text
トランザクションスクリプトとの戦いかた ● ほとんどが機能を実現しているロジック ● 関数呼び出しはほとんどモックで置き換えた ● それでも通せない重複した構造のコードが多過ぎた => ここで取捨選択をすることに決定 20
Slide 21
Slide 21 text
トランザクションスクリプトとの戦いかた 前提 ● 見えている部分のみテストできればよい ● 呼び出し先はテスト済みのはず 新たな方針 ● 内部状態は問題にしない ● コンパイルが通るような状態なら充分である ● 通せないものは通せない 21
Slide 22
Slide 22 text
トランザクションスクリプトとの戦いかた 守りたいもの ● 文法的な正しさを担保すること ○ たとえそれが手作業であったとしても 捨てても構わないもの ● カバレッジ 100% という安心感 22
Slide 23
Slide 23 text
カバレッジ取得しなかったもの ● return だけしているブロック ○ 戻り値のチェックをしたいわけではない ● 単純な操作のみのブロック ○ 文字列結合だけしている ○ 変数に代入しているだけ ● 例外を投げているだけのブロック ○ 投げるだけならエラーにはならないはず ○ レアケースが多すぎるため、コストが高すぎる 23
Slide 24
Slide 24 text
無事生還 24
Slide 25
Slide 25 text
まとめ ● 切り分けは大事 ○ コアロジックはしっかりテストしよう ○ 構文のテストがいるような個所も ● 知識は詰め込めばわりと入る ○ この経験で PHP に対して知見が深まったのは事実 ○ 言語化できるにはまだ壁がある状態 ● コンパイラがある幸せ ○ みんな Scala やろう 25