1. 概要

このチュートリアルでは、MockitoのAdditionalAnswersクラスとそのメソッドについて説明します。

2. 引数を返す

AdditionalAnswers クラスの主な目的は、モックされたメソッドに渡されたパラメーターを返すことです。

たとえば、オブジェクトを更新する場合、モックされるメソッドは通常、更新されたオブジェクトを返すだけです。 AdditionalAnswers のメソッドを使用すると、代わりに、パラメーターリスト内の位置に基づいて、メソッドに引数として渡された特定のパラメーターを返すことができます。

さらに、 AdditionalAnswers には、Answerクラスのさまざまな実装があります。

デモンストレーションを開始するには、ライブラリプロジェクトを作成しましょう。

まず、1つの単純なモデルを作成します。

public class Book {

    private Long bookId;
    private String title;
    private String author;
    private int numberOfPages;
 
    // constructors, getters and setters

}

さらに、本を取得するためのリポジトリクラスが必要です。

public class BookRepository {
    public Book getByBookId(Long bookId) {
        return new Book(bookId, "To Kill a Mocking Bird", "Harper Lee", 256);
    }

    public Book save(Book book) {
        return new Book(book.getBookId(), book.getTitle(), book.getAuthor(), book.getNumberOfPages());
    }

    public Book selectRandomBook(Book bookOne, Book bookTwo, Book bookThree) {
        List<Book> selection = new ArrayList<>();
        selection.add(bookOne);
        selection.add(bookTwo);
        selection.add(bookThree);
        Random random = new Random();
        return selection.get(random.nextInt(selection.size()));
    }
}

これに対応して、リポジトリメソッドを呼び出すサービスクラスがあります。

public class BookService {
    private final BookRepository bookRepository;

    public BookService(BookRepository bookRepository) {
        this.bookRepository = bookRepository;
    }

    public Book getByBookId(Long id) {
        return bookRepository.getByBookId(id);
    }

    public Book save(Book book) {
        return bookRepository.save(book);
    }

    public Book selectRandomBook(Book book1, Book book2, Book book3) {
        return bookRepository.selectRandomBook(book1, book2, book3);
    }
}

これを念頭に置いて、いくつかのテストを作成しましょう。

2.1. 最初の引数を返す

テストクラスでは、MockitoJUnitRunner で実行するJUnitテストクラスにアノテーションを付けることで、Mockitoテストでアノテーションを使用できるようにする必要があります。 さらに、サービスとリポジトリクラスをモックする必要があります。

@RunWith(MockitoJUnitRunner.class)
public class BookServiceUnitTest {
    @InjectMocks
    private BookService bookService;

    @Mock
    private BookRepository bookRepository;

    // test methods

}

まず、最初の引数を返すテストを作成しましょう– AdditionalAnswers.returnsFirstArg()

@Test
public void givenSaveMethodMocked_whenSaveInvoked_ThenReturnFirstArgument_UnitTest() {
    Book book = new Book("To Kill a Mocking Bird", "Harper Lee", 256);
    Mockito.when(bookRepository.save(any(Book.class))).then(AdditionalAnswers.returnsFirstArg());

    Book savedBook = bookService.save(book);

    assertEquals(savedBook, book);
}

つまり、Bookオブジェクトを受け入れるBookRepositoryクラスのsaveメソッドをモックします。

このテストを実行すると、実際に最初の引数が返されます。これは、保存したBookオブジェクトと同じです。

2.2. 2番目の引数を返す

次に、 AdditionalAnswers.returnsSecondArg()を使用してテストを作成します。

@Test
public void givenCheckifEqualsMethodMocked_whenCheckifEqualsInvoked_ThenReturnSecondArgument_UnitTest() {
    Book book1 = new Book(1L, "The Stranger", "Albert Camus", 456);
    Book book2 = new Book(2L, "Animal Farm", "George Orwell", 300);
    Book book3 = new Book(3L, "Romeo and Juliet", "William Shakespeare", 200);

    Mockito.when(bookRepository.selectRandomBook(any(Book.class), any(Book.class),
      any(Book.class))).then(AdditionalAnswers.returnsSecondArg());

    Book secondBook = bookService.selectRandomBook(book1, book2, book3);

    assertEquals(secondBook, book2);
}

この場合、 selectRandomBook メソッドを実行すると、メソッドは2番目の本を返します。

2.3. 最後の引数を返す

同様に、 AdditionalAnswers.returnsLastArg()を使用して、メソッドに渡した最後の引数を取得できます。

@Test
public void givenCheckifEqualsMethodMocked_whenCheckifEqualsInvoked_ThenReturnLastArgument_UnitTest() {
    Book book1 = new Book(1L, "The Stranger", "Albert Camus", 456);
    Book book2 = new Book(2L, "Animal Farm", "George Orwell", 300);
    Book book3 = new Book(3L, "Romeo and Juliet", "William Shakespeare", 200);

    Mockito.when(bookRepository.selectRandomBook(any(Book.class), any(Book.class), 
      any(Book.class))).then(AdditionalAnswers.returnsLastArg());

    Book lastBook = bookService.selectRandomBook(book1, book2, book3);
    assertEquals(lastBook, book3);
}

ここで、呼び出されたメソッドは3番目の本を返します。これは、最後のパラメーターであるためです。

2.4. インデックスで引数を返す

最後に、を使用して、指定されたインデックス AdditionalAnswers.returnsArgAt(int index)で引数を返すことができるメソッドを使用してテストを作成しましょう。

@Test
public void givenCheckifEqualsMethodMocked_whenCheckifEqualsInvoked_ThenReturnArgumentAtIndex_UnitTest() {
    Book book1 = new Book(1L, "The Stranger", "Albert Camus", 456);
    Book book2 = new Book(2L, "Animal Farm", "George Orwell", 300);
    Book book3 = new Book(3L, "Romeo and Juliet", "William Shakespeare", 200);

    Mockito.when(bookRepository.selectRandomBook(any(Book.class), any(Book.class), 
      any(Book.class))).then(AdditionalAnswers.returnsArgAt(1));

    Book bookOnIndex = bookService.selectRandomBook(book1, book2, book3);

    assertEquals(bookOnIndex, book2);
}

最後に、インデックス1から引数を要求したので、2番目の引数(この場合は book2 )を取得します。

3. 機能インターフェイスからの回答の作成

AdditionalAnswers は、機能インターフェイスから回答を作成するための簡潔でわかりやすい方法を提供します。 そのために、 answer()と answerVoid()。の2つの便利なメソッドが用意されています。

それでは、うさぎの穴を下って、実際の使い方を見てみましょう。

これらの2つのメソッドには、@Incubatingという注釈が付けられていることに注意してください。 これは、コミュニティのフィードバックに基づいて、後で変更される可能性があることを意味します。

3.1. AdditionalAnswers.answer()を使用する

このメソッドは主に、機能インターフェイスを使用してJava8で強く型付けされた回答を作成するために導入されました。

通常、Mockitoには、モックの回答を構成するために使用できる、すぐに使用できる汎用インターフェースのセットが付属しています。 たとえば、Answer1を提供します単一の引数の呼び出しの場合

次に、 AdditionalAnswers.answer()を使用して、Bookオブジェクトを返す回答を作成する方法を説明します。

@Test
public void givenMockedMethod_whenMethodInvoked_thenReturnBook() {
    Long id = 1L;
    when(bookRepository.getByBookId(anyLong())).thenAnswer(answer(BookServiceUnitTest::buildBook));

    assertNotNull(bookService.getByBookId(id));
    assertEquals("The Stranger", bookService.getByBookId(id).getTitle());
}

private static Book buildBook(Long bookId) {
    return new Book(bookId, "The Stranger", "Albert Camus", 456);
}

上に示したように、メソッドリファレンスを使用して、Answer1インターフェイスを示しました。

3.2. AdditionalAnswers.answerVoid()を使用する

同様に、 answerVoid()を使用して、何も返さない引数呼び出しに対するモックの回答を構成できます。

次に、テストケースを使用した AdditionalAnswers.answerVoid()メソッドの使用例を示します。

@Test
public void givenMockedMethod_whenMethodInvoked_thenReturnVoid() {
    Long id = 2L;
    when(bookRepository.getByBookId(anyLong())).thenAnswer(answerVoid(BookServiceUnitTest::printBookId));
    bookService.getByBookId(id);

    verify(bookRepository, times(1)).getByBookId(id);
}

private static void printBookId(Long bookId) {
    System.out.println(bookId);
}

ご覧のとおり、 VoidAnswer1を使用しましたへのインターフェース何も返さない単一の引数呼び出しに対する回答を作成する

answer メソッドは、モックと対話するときに実行されるアクションを指定します。 この場合、渡された本のIDを出力するだけです。

4. 結論

全体として、このチュートリアルでは、MockitoのAdditionalAnswersクラスのメソッドについて説明しました。

これらの例とコードスニペットの実装は、GitHubから入手できます。