✍️ inakam’s blog

inakamの思考置き場

🚿 クリーンアーキテクチャとテストモックって相性が悪いのでは?という話

image block

クリーンアーキテクチャに入門した

最近はどこを見てもクリーンアーキテクチャなので、クリーンアーキテクチャに入門してみました。

わりと新しいアーキテクチャが提案されても、依存の方向性を一方向に揃えるという原則が守られていたりして、多くの場合はクリーンアーキテクチャの変形のように考えられる気がしています。

自分は業務ではGoでAPIを作成する派閥なので、Goでクリーンに書いてみましたが、リファクタリングのしやすさなど、(おそらくJavaを参考に考えられた思想であっても)十分にその恩恵をうけることができた気がします。

どうやってテストをするか

そしてクリーンアーキテクチャにおいてテストをどうするかを悩むという部分があり、

というのも今回作成したアプリケーションはそこまで規模が大きいものではなく、あまり自動テストのために工数を割きたくなかったため、テストはちゃちゃっと書きたかった。そこでいつものようにモッキングしながらテストを作成しようとしたが、以下のような問題にぶちあたります。

オニオンアーキテクチャ
image block

クリーンアーキテクチャにおいて有名なのはこのオニオンアーキテクチャだろうと思うので、この図の通りに説明をしていくと、まずテストを行おうと思うと挙動が正しいかを確認したいので、外側の層(例えばアプリケーション層など)への入力を行い、出力が正しいかをテストしようとする。

そうなると、内側の層をモックすることになる。そしてモックはあくまでモックなので、実際に内側の層が正しく動作しているかを別のテストを作成しなくてはならなくなる。すると、さらに内側のドメインサービス層のテストが必要になり、ドメイン層をモックにするので、そうなるとドメイン層のテストは別に必要なり・・・と言う感じで、テストを網羅するには全ての層にテストを入れる必要が出てきてしまいます。

ロンドン派とデトロイト派

テストの考え方としてモックを使うか使わないかはロンドン派とデトロイト派に別れるらしいです。自分はモックを使おうと言っておきながら、普段のテストでは基本的にモックを使わないのでどちらかというとデトロイト派なんでしょう。

テスト作成コスト

テストを作るのもただじゃない

人によってはクリーンアーキテクチャでモックを使うなら全部の層でテストをすればいいじゃないかという人もいるかもしれないんですが、そうなるとテスト作成コストがかかります。

この議題を考え始めたきっかけたが、自分が立ち上げのソフトウェアを書き、今は自分の手から離れているプロジェクトがあるのですが、それはまさにクリーンアーキテクチャ+モックテストの構成をとっており、かなりの数のテストを頑張って仕込みました。しかし、時が経つにつれてわかったことは、テストを作るのは簡単ではなく工数もかかるということです。

新機能の開発をするために全部の層にテストを仕込むのは大変であり、しかもそのテストがあまり品質の向上に寄与していないということも大いに考えられました。

モックは機能するものじゃない

同時に思うのは、モックは実際のソフトウェアとして機能するものではないということです。モックをいくら上手に作ったとしても実際の機能には何ももたらしません。

テストが変更容易性を下げてしまう

またモックがあまりにも多くあると、リファクタリング時にそれらのテストも修正する必要が出てきてしまい、それがソフトウェアの変更容易性を大きく下げてしまうことも考えられます。層ごとにテストを入れてしまうとこの問題の方が比較的大きい気がします。

ドメインモデルやDBだけをモックすればいいか?

ここまで書いておいて、ドメインモデルやDBだけをモックすればいい気がしてきました。ただこれはGoの事情ですが、別パッケージとして切っていて、外側の層からドメイン層を直接モッキングできない状態などになっていると、やはりそれぞれにテストを書く必要があり、テスト作成コストは少し高い状態が続いてしまう気もします。

結局どうするか?

自分はいろいろなことを考えながら、最終的にはローカルにおけるテストではDockerを使ってテストデータを流し込んだDBを立ち上げ、アプリケーション層(外側の層)のみのテストを行うということを選びました。

実際に近いデータで外側の層で入出力が正しくできるかさえテストすれば、実際の機能には問題がないことを確かめられ、リファクタリングもしやすいです。

どこまで細かくテストするんだろう?ということなんだとは思うんですが、クリーンアーキテクチャの恩恵は受けつつ、最小工数で品質の高いコードを書きたいものです。