TotT: 詳細クラスのテストより、公開APIのテストを優先しよう
こんにちは、kubopです。
Googleにはトイレテスト(TotT)という文化があるようで、テストに関するTipsをトイレに貼り出し、テストに関する知識を全社で共有しているらしいです。
昨今はリモート勤務が広まり、TotTの実施は難しく、SlackやBotを用いてもなかなか浸透するかどうか…
そこで、noteに書きつつ自分が勉強するために、少しずつ読んで内容や、所感を書いてみようと思います。
※ 翻訳・解釈の間違いなどあるかもしれません。
その場合はこっそり教えてください。
Testing on the Toilet: Prefer Testing Public APIs Over Implementation-Detail Classes
以下のクラスには、テストが必要だと思いますか?
class UserInfoValidator {
public void validate(UserInfo info) {
if (info.getDateOfBirth().isInFuture()) { throw new ValidationException()); }
}
}
UserInfoValidatorには分岐などのロジックがあるため、テストがあることは良いかもしれません。
しかし、UserInfoValidatorを利用するクラスが、唯一UserInfoServiceだけだったとしたらどうでしょう?
public class UserInfoService {
private UserInfoValidator validator;
public void save(UserInfo info) {
validator.validate(info); // Throw an exception if the value is invalid.
writeToDatabase(info);
}
}
答えは、「UserInfoServiceを通してすべてのパスをテストすることができるので、おそらくテストは必要ない」です。
重要な違いは、このクラスは実装の詳細であり、公開APIではないということです。
--
パブリックなAPIはどこからでも複数から呼び出しがあり、ユーザーはそのメソッドに可能な限りの組み合わせの入力を渡すことができます。
そのため、APIを利用する際に問題が発生しないように十分にテストされていることが必要です。
※パブリックAPIの例としては、コードベースの異なる部分で使用されるクラス(例えば、クライアントサイドで使用されるサーバーサイドのクラス)や、コードベース全体で使用される共通のユーティリティクラスがあります。-> ControllerやServiceなど。
実装詳細クラスは、公開APIをサポートするためだけに存在し、依存関係が限られています。
これらのクラスは、それらを使用する公開 API をテストすることで、間接的にテストすることができます。
実装詳細クラスのテストは、クラスが複雑な場合や公開 API クラスのテストを書くのが大変な場合などの場合は有効です。
実装詳細クラスをテストする場合は、そのメソッドに渡されることのない入力があるため、パブリックAPIほど深くテストする必要はありません。
(上記のコードサンプルでは、UserInfoValidator.validateへの引数としてNULLが渡されると何が起こるかをテストしても意味が無い。)
実装詳細クラスは、別のクラスにたまたま存在するプライベートメソッドと考えることができます。実装詳細クラスは、可視性を制限するようにしましょう。
実装の詳細なクラスを頻繁にテストすると、いくつかの問題が発生します。
実装詳細クラスのリファクタ時にテストもリファクタする必要があるため、コードの保守が困難になる。
実装詳細クラスだけテストを行う場合、APIの動作は保証されず、複数の呼び出しパターンに対応できません。
🤔
Rubyで書くとこんな感じかなぁと予想。
class UserInfoValidator
def validate(user_info)
raise ValidationException if info.getDateOfBirth().isInFuture()
end
end
class UserInfoService
def self.save(user_info)
UserInfoValidator.new().validate(user_info)
user_info.save
end
end
UserInfoValidator.validate()はprivateメソッドと同じ扱いになるので、テストは不必要な感じなのかな。
rubyだとpackage-privateは難しそうだから、利用が複数に散らばらないように考える必要があるかも。
Licensed under a Creative Commons
Attribution–ShareAlike 4.0 License