6
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

LaravelAdvent Calendar 2022

Day 5

FeatureTestとユニットテストの使い分けについて

Last updated at Posted at 2022-12-07

LaravelでTDDしていますか?

Laravelのプロジェクトを新規作成すると、tests/Feature, tests/Unitディレクトリがついてきます。
tests/Featureの下にはFeatureテスト、tests/Unitの下にはユニットテストを書いてほしそうな構成です。

では、あなたのユニットテストが継承しているTestCaseクラスは Tests\TestCase でしょうか、それとも PHPUnit\Framework\TestCase でしょうか?
もちろん、 Tests\TestCase 自体が PHPUnit\Framework\TestCase を継承しているので、 extends Tests\TestCase なテストであっても PHPUnit\Framework\TestCase を継承はしています。

Tests\TestCaseはsetUp()でLaravelのapplicationを起動しています。
Laravelのapplicationが起動されていることによって、テスト時もFacade等の便利な機能が使えるというメリットがあるわけですが、一方でデータベースアクセスがあるクラスをテストするとテスト時にもデータベースを使ってしまうというデメリットがあります。
こうなると、テスト対象のクラス内には問題がなくてもDBデータやDBサーバーの状態によってテストが不安定になってしまいます(落ちやすくなる、結果が一定でなくなる)。

ユニットテストは「PHPUnitを使って書いたテスト」ではなく、「1つのクラスだけ独立して動かせるテスト」になるように書きましょう。
そして、ユニットテストを独立したテストとして書くためにはテストコードでなくプロダクションコード(テスト対象となるコード)の側を、ユニットテストできるように配慮して書く必要があります。

具体的には、 ユニットテストを書きたいぐらい複雑なクラスに対しては

  • Laravelの提供するFacadeを使わずにFacade rootにあたるinterfaceをDIして利用する
  • Modelのstaticメソッドを直接使わずサービスクラスを挟む(Repositoryパターンにしても良い)

のような工夫をすると良いです。

ユニットテストではモックした分、FeatureTestでは、ユニットテスト済の自分のクラスがデータベースやLaravelの機能と統合されたときに意図通りに動くかをテストできるように書きましょう。

その他tips

Laravel特有の配慮でなく、一般的なPHPコードに対するユニットテストを書きやすくする工夫については、PHPカンファレンス北海道2019のアンカンファレンスで話した テストを助けに使って設計を改善しよう~リファクタリングことはじめ~ にまとめていますので興味のある方はあわせてご覧ください。

6
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?