みなさんこんにちは
先月よりジョインしました、
niisan-tokyo
です。
今後とも宜しくお願いします。
で、今回のテーマですが、以前にkotamatが公開していた、テストを通したAPIスペックの自動生成プラグインをちょいと改造したという話です。
APIスペック自動生成ツールの改造
TL;DR
対象のリポジトリ
https://github.com/kotamat/laravel-apispec-generator
ちょっと使いにくかった
このプラグインは、使い方は容易だったのですが、一つ欠点がありました。
それは、このプラグインをベースクラスとして継承しなければならないということです。
<?php use ApiSpec\ApiSpecTestCase; class TestCase extends ApiSpecTestCase { }
APIスペックを出力する必要のないところでは、このクラスを継承したくないため、別のベースクラスを使いたくなりますが、一方で、ベースクラスでアプリで特有の設定やら便利なテスト機能を実装することがあるでしょう。
結局、普通のベーステストクラスとともに、APIスペック出力用のクラスを継承したベーステストクラスを用意するという、少々厄介なことになります。
traitにする
そこで、ベースクラスの代わりにtraitを使うという技が考えられます。
traitは使用することで、そのクラスに単純にtraitの中のコードをコピーしたのと同じ状態を作ることができます。
ApiSpecTestCase
は、実際にはいくつかのメソッドにAPI仕様を吐き出すコードを入れているだけですので、traitで十分ということになります。
traitを使う場合のAPI仕様の出力は以下のようにすると可能になります。
<?php use ApiSpec\ApiSpecOutput; class SomeTestCase extends TestCase { use ApiSpecOutput; //... /** * @test */ public function API仕様を吐き出すテスト() { $this->isExportSpec = true; $this->getJson('/someone/status'); } }
こうして、必要なときにだけ、use ApiSpecOutput
することで、ベースクラスをいじることなく、API仕様を吐き出すことができます。
後方互換性の維持
こうして、traitにしようとしたときに、すでにベースクラスで使っているところはどうなるんだという話になります。
これは、プロダクト開発において、仕様を追加する場合にも発生する問題で、後方互換性をどうするのかということです。
今回は後方互換性は残すことにします。
後方互換性の確保の方法は簡単で、要するにテストが通っていればいいということです。
API仕様出力ベースクラスはテストクラスのベースクラスなので、テストの方法が厄介でした。
テスト自体はかなり無理矢理なコードでとにかくテストできればいいやって感じになっています。
<?php // ... 中略 public function createApplication() { $app = new class extends Application { private $acceptor; public function __construct($basePath = null) { // } public function setAcceptor($acceptor) { $this->acceptor = $acceptor; } public function make($class, array $param = []) { $mock = m::mock(FilesystemAdapter::class); $mock->shouldReceive('drive')->andReturn($this->acceptor); return $mock; } }; $app->setAcceptor($this->acceptor); $this->app = $app; } protected function setUp() { $this->acceptor = new class { public $filename; public $str; public function put($filename, $str) { $this->filename = $filename; $this->str = $str; } }; $this->createApplication(); }
これがテストの前提部分ですね。
無名クラスを連発しておきながら、思い出したようにMockeryを利用したりしています。
テスト部分は上のリンクで見てください。単純にpostJson
とかを投げたら、API仕様の出力ができていることを確認しているだけです。
このテストを作った上で、ApiSpecTestCase
にあったロジックの大半をApiSpecOutput
に移し、ApiSpecTestCase
はApiSpecOutput
を使っているだけという状態にすることができました。
まあ、ベースクラスに手を入れずに、traitだけ作ればこんな苦労はないんですが、同じコードがあるって気持ち悪いので、やってしまいしました。
まとめ
というわけで、API仕様の出力をtrait化することに成功しました。
個人的にはもうちょい改造したいところですが、ひとまずはtraitで使えるようになったというところで満足しておきましょう。
今回はこんなところです。
最後に
現在、株式会社SCOUTERでは、エンジニア、デザイナーの募集をしております。
興味のある方は、是非下記からご応募お願い致します!