4

変更可能なエンティティを使用するサービスをテストする必要がある場合は、必要な最小のオブジェクト (実際のオブジェクト) を作成してサービスに渡します。例:

User joe = new User();
joe.setEmail("joe@example.com");

resetPasswordService.resetPassword(joe);

verif(emailServiceMock).sendEmail("joe@example.com", "Your password has been reset!");

明らかに User には多くのフィールドがありますが、resetPasswordService必要ないので設定しません。メールではない User フィールドの名前を変更しても、このテストは変更されないため、これは非常にリファクタリングに適しています。

Immutablesオブジェクトで同じことをしようとすると、問題が発生します。同じ例に固執し、ユーザーをエンティティから不変に変えます。

@Value.Immutable
public abstract class User {
    public abstract String getEmail();
    public abstract PostalAddress getPostalAddress();
    //more fields
}

User joe = new ImmutableUserBuilder().email("joe@example.com").build();

resetPasswordService.resetPassword(joe);

verif(emailServiceMock).sendEmail("joe@example.com", "Your password has been reset!");

java.lang.IllegalStateException: ユーザーを作成できません。必要な属性の一部が設定されていません [postalAddress、signupDate、city、....]

オブジェクトを構築しようとすると、これはビルダーで失敗します。それで、私は何をすべきですか?

  • ユーザーにモックを使用し、モックがモックを返すたびに妖精が死んでもモックを返すようにします
  • テスト用の DSL を作成し、必要のないすべてのフィールドを含むユーザー ツリー構造全体を構築するためのある種のファクトリを用意しますか? 重く、リファクタリングしにくいようです。これにより、テストの要件がそれほど透明ではなくなります。
  • ユーザーのすべてのフィールドを作成@Nullableし、ビルダーにオブジェクトを検証させませんか? これにより、実稼働環境に不完全なオブジェクトが存在するリスクにさらされることになりますよね?
  • 私が逃した他のオプション?

ユーザーは不変の値オブジェクトではなく、エンティティであるべきだと私は知っています。分かりやすいので、この例では User を使用しました。

4

2 に答える 2

3

テストは現在、パスワード リセット機能の実装の詳細に依存しています。

これは、テストする動作です

  • 与えられたユーザー
  • そのユーザーがパスワードのリセットを要求したとき
  • その後、メールが送信されます

後でパスワードのリセット機能を変更して、メールに名前が含まれるようにしたとします。

親愛なるジョーへ

パスワードのリセットをリクエストしました...

インスタンスが名前を必要としないNullPointerExceptionという仮定に基づいてテスト戦略を立てたため、テストは失敗します。User完全に無害な変更により、テストがまだ成功するはずなのに、テストが失敗してしまいました。

解決策: 実際のオブジェクトを使用します。さまざまなテストで多数のユーザーを作成していることがわかった場合は、ユーザー作成を独自の機能にリファクタリングします。

private User getUser()
{
    User joe = new User();
    joe.setEmail("joe@example.com");
    joe.setName("Joe");
    joe.setAge(20);
    joe.setHeight(180);
    return joe;
}
于 2017-08-30T10:02:17.980 に答える