CakePHP Fixture Factoriesの登場によって変化する、PHPプロジェクトにおけるテストフィクスチャ管理の選択肢
TODO: これを読むこと
構造
概要
前提
(おさらい)xUnitとは?
コンピュータプログラムの単体テスト(ユニットテスト)を行うためのテスティングフレームワークの総称である。これらのフレームワークでは、関数やクラスなど、ソフトウェアの様々な要素(ユニット)をテストすることができる。xUnitフレームワークの主な利点は、テストを自動化できること、同じテストを何度も書かずに済むこと、個々のテストの結果がどうあるべきかを覚えておかなくても良いことである。
では What's テストフィクスチャ
テストを実行、成功させるために必要な状態や前提条件の集合を、フィクスチャ(英語版)と呼ぶ。これらはテストコンテキストとも呼ばれる。開発者はテストの実行前にテストに適した状態を整え、テスト実行後に元の状態を復元することが望ましい。
テストフィクスチャは前提条件となるもの全てを指してる
データベースにレコードを登録するアプリだったら、データベース(および事前に必要になるレコード)がテストフィクスチャ
文字をトークナイズするライブラリだったら、自然言語のテキストたちがテストフィクスチャ
小さなライブラリなら単なる文字列とか配列とかもそう
つまり、自動テストにおけるテストフィクスチャは、数多の種類のデータを扱うであろう、ほぼ全てのソフトウェアにおいて必要になるテクニック
その中でもデータベースと密接に連携する Web アプリケーションにおいては、データベースにデータを投入し、そのデータをテストフィクスチャとして利用するテクニックは初期の頃から利用されてきました。
例えば、MVCフレームワークを採用したアプリでいうModel層のテストケースがほしいとする
入力されたデータが正常にデータベースに登録されるか、を検査したい
それユニットテストか...?って話はご愛嬌
「どんくらい昔からやってるのそれ?」
そして、Rails 2.x の段階ではすでにテストフィクスチャについて RailsGuides に言及されていた ので、まあフルスタックフレームワークが登場した初期の頃(2008年くらい)から存在すると言ってよさそう
ちょっとこの辺調べきれてないので誰かたのんだ...
@t_wada「エリック・ガンマとケント・ベックが、チューリッヒからアトランタまでのフライトの中で"SUnitをJUnitに移植する"という伝説のペアプロを行った、ってのがあって、それが今年(2022年)で25年」 @t_wada「「TDD原著が出たのも言葉が生まれた直後。2002年だった、と」 e.g. テストフィクスチャがフルスタックフレームワークでどう装備されてる??
YAMLファイルとか定義してDBに取り込む ActiveRecord::FixtureSet ってクラスがある
PHPファイルに配列を書いて定義するかんじ
おっと?? Model Factories という概念を使ってるね??
Laravel 5.3くらいからあるっぽい?誰か補足して...
テストフィクスチャの種類を大別すると
In-line setup(インライン)
In-line setup creates the test fixture in the same method as the rest of the test. While in-line setup is the simplest test fixture to create, it leads to duplication when multiple tests require the same initial data.
テストケース内で定義される形式
Delegate setup(委任)
Delegate setup places the test fixture in a separate standalone helper method that is accessed by multiple test methods.
複数のテストメソッドから呼ばれるstandaloneなヘルパーメソッドを経由して呼び出される形式
Implicit setup(暗黙的)
Implicit setup places the test fixture in a setup method which is used to set up multiple test methods. This differs from delegate setup in that the overall setup of multiple tests is in a single setup method where the test fixture gets created rather than each test method having its own setup procedures and linking to an external test fixture.
単一のセットアップ処理で生成されて、それが複数のテストメソッドから呼び出される
To execute an automated test, we require a text fixture that is well understood and completely deterministic. Setting up a Fresh Fixture (page X) can be time consuming, especially when dealing with complex system state stored in a test database.
完全に決定論的に理解された"テストフィクスチャ"が自動テストの実行には必要である、 #トノコト "text fixture" はtypoっぽい
決定論(けっていろん、英: determinism、羅: determinare)とは、あらゆる出来事は、その出来事に先行する出来事のみによって決定している、とする哲学的な立場。
要は固定されたテキストフィクスチャが用いられるべき、 #トノコト つまり、自動テストの高速化にはできるだけテストフィクスチャを一括で用意して、それを用いる方が効果的なんだよ!って話なんだね
そもそも自動テストに高速化って必要なんだっけ?? #要出典 まあ大風呂敷広げたけど、結局は何を使うのが正解?
このへん、SWEの本にも「テストは繰り返し実行するから速度が大事」的なこと書いてあった気がする #要出典 重要なのは、テストフィクスチャを複雑でも柔軟に表現できる"表現力"があると便利!ってこと
じゃあ、どう複雑なものを柔軟に表現するの??
これのおかげで、Laravelでは既に実現されてるModel FactoriesをCakePHPで使えるようになった🙌 具体的にはこんな感じに使えるよん
基本的に class UserFactory extends BaseFactory というかんじで読み込む
UserFactory::make() でModel Factoryがセットアップされる
この時点ではclass UserFactoryに定義されてる protected function setDefaultTemplate(): void の中で定義されているデータをセットアップするだけ
$userArray = UserFactory::make()->getEntity() で配列になったデータが出てくる
CakePHPだと UserFactory::make()->persist()とかってやると cakephp/orm の class Cake\ORM\Table で定義された class UsersTable extends Table でデータが保存されて、 class Cake\ORM\Entity で定義されてる class App\Model\Entity\User extends Entity のインスタンスがヒュッと手に入る! そして UserFactory::make()->with('UserAddresses', UserAddressFactory::make(3)) みたいなかんじで簡単にassociationsも表現できる!!!
基本的にCakePHP3で導入された cakephp/orm のTableクラスとEntityクラスを前提に実装されてる CakePHP2はがんばったら使えるかもだけど恩恵はあまり受けられないかな... フレームワークの前提が namespaced じゃないので、どう読み込むかは課題だけどたぶん使えそうではあるけど公式にはサポートされてないし、そもそもEntityの恩恵は得られない
UserFactory::make()->getEntity()でデータが手に入るまでは一緒
データベースへ登録するには cakephp/orm に準拠したTableクラスとEntityクラスが必要になる
将来的には拡張ができるようになるかもしれないけど、現状は一通りEventCompilerとかを書かないと差し替えられないね...
他の言語だと??(時間が余れば)
おわりに(まとめ)
お砂場
自動テストにおけるテストフィクスチャ(Test fixture, 場合によってはテストコンテキストとも呼ぶ)は、数多の種類のデータを扱うであろう、ほぼ全てのソフトウェアにおいて必要になるテクニックです。
その中でもデータベースと密接に連携する Web アプリケーションにおいては、データベースにデータを投入し、そのデータをテストフィクスチャとして利用するテクニックは初期の頃から利用されてきました。
PHPにおいては、各種フルスタックフレームワークにテストフィクスチャを管理する機能が備わったりしていますが、一方で Fabricate という Ruby における factory_bot のような"柔軟な定義構文を用いてテストフィクスチャを管理する"ためのパッケージや、ここ最近になって CakePHP Fixture Factories という Fabricate に近しいコンセプトでテストフィクスチャを扱うパッケージが登場してきています。
本セッションでは、新たに登場した CakePHP Fixture Factories の解説を踏まえ、CakePHP ではない PHP プロジェクトでも CakePHP Fixture Factories が転用できる可能性を示しつつ、新たなテストフィクスチャのスタンダードについてお話できればと思います。
決定稿
自動テストにおけるテストフィクスチャは、ほぼ全てのソフトウェアにおいて必要になるテクニックです。その中でもデータベースと密接に連携する Web アプリケーションにおいては、データベースにデータを投入し、そのデータをフィクスチャとして利用するテクニックは初期の頃から利用されてきました。
PHPにおいては、 Fabricate という Ruby における factory_bot のような"柔軟な定義構文を用いてフィクスチャを管理する"ためのパッケージや、ここ最近になって CakePHP Fixture Factories という Fabricate に近しいコンセプトのパッケージが登場してきています。
本トークでは、最近登場した CakePHP Fixture Factories の解説を中心に、新たなテストフィクスチャ管理ツールのスタンダードについてお話できればと思います。
(393文字)
残骸
Static Fixtures
決まった値を流し込む
いつ?
テストスイートを一通り流す前とか
何がうれしい?
速い(テストケース実行時にはすでにオンメモリだし)
Dynamic Fixtures
動的に値を生成する
いつ?
テストケースを実行する前
何がうれしい?
柔軟(テストケースに合わせて準備するしね)
ストレージはStaticでもDynamicでも変わんない??
結局は値なので
直で値定義
ファイルに値
DBに保存
DBって便利なのよね
ID自動採番されるしシュンって取得できるしfilterもmapもreduceもSQLでできる
値の状態変化を追いつつテストする、みたいなこともしてそう
何でStatic/Dynamicを分けるのか
Hot/Coldでもよいかもめ
参考