stmtkブログ

Python中心の技術ブログです。

【Java】Mockitoでモック化したメソッドの引数を検証する方法

Mockitoでモック化したメソッドの引数を検証する方法です。

JunitはJunit4を使用しています。

引数が基本型の場合

以下のような基本型の引数の場合のケースです。

StringやLocalDateなどの参照型でも基本型に扱いが近しいものはこのケースに含まれます。

public void execute1(int no) {
    // do something
}

verify対象のメソッドの引数に想定の値をセットすればOKです。

verify(logic, times(1)).execute1(1); // OK

引数が参照型の場合(同一インスタンス

以下のような参照型の引数の場合のケースです。

なおかつ、引数をテストクラスから直接渡せるケースです。

public void execute2(Dto dto) {
    // do something
}

verify対象のメソッドの引数にテストクラスで作成したインスタンスをセットすればOKです。

Dto dto = new Dto();
dto.setNo(1);
verify(logic, times(1)).execute2(dto); // OK

引数が参照型の場合(フィールドが基本型のみ)

以下のような参照型の引数の場合のケースです。

なおかつ、引数をテストクラスから直接渡せない、かつ、参照型クラスのフィールドが基本型のみのケースです。

public void execute3(Dto dto) {
    // do something
}

テストクラスで作成したインスタンスと実際にメソッドに渡されるインスタンスが異なるため、こういう場合はArgumentMatchersのrefEq()が有効です。

Dto dto = new Dto();
dto.setNo(1);
verify(logic, times(1)).execute3(dto); // NG
verify(logic, times(1)).execute3(refEq(dto)); // OK

引数が参照型の場合(フィールドに参照型が含まれる)

以下のような参照型の引数の場合のケースです。

なおかつ、引数をテストクラスから直接渡せない、かつ、参照型クラスのフィールドに別の参照型クラスが含まれるケースです。

public void execute4(NestDto nestDto) {
    // do something
}

refEq()はフィールドに参照型が含まれていると使えないため、ArgumentMatchersのargThat()が有効です。

argThat()には任意のArgumentMatcherを指定できるので、ArgumentMatcherを作成してフィールドを検証します。

NestDto nestDto = new NestDto();
nestDto.setDto(new Dto());
nestDto.getDto().setNo(1);
verify(logic, times(1)).execute4(refEq(nestDto)); // NG

ArgumentMatcher<NestDto> matcher = argument -> {
    assertThat(argument.getDto().getNo(), is(1));
    return true;
};
verify(logic, times(1)).execute4(argThat(matcher)); // OK

ソースコード

import lombok.Getter;
import lombok.Setter;

@Getter
@Setter
public class Dto {
    private int no;
}
import lombok.Getter;
import lombok.Setter;

@Getter
@Setter
public class NestDto {
    private Dto dto;
}
public class Logic {

    public void execute1(int no) {
        // do something
    }

    public void execute2(Dto dto) {
        // do something
    }

    public void execute3(Dto dto) {
        // do something
    }

    public void execute4(NestDto nestDto) {
        // do something
    }

}
public class Sample {

    public void execute1(Logic logic) {
        logic.execute1(1);
    }

    public void execute2(Logic logic, Dto dto) {
        logic.execute2(dto);
    }

    public void execute3(Logic logic) {
        Dto dto = new Dto();
        dto.setNo(1);
        logic.execute3(dto);
    }

    public void execute4(Logic logic) {
        NestDto nestDto = new NestDto();
        nestDto.setDto(new Dto());
        nestDto.getDto().setNo(1);
        logic.execute4(nestDto);
    }

}
import org.junit.Test;
import org.mockito.ArgumentMatcher;

import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.ArgumentMatchers.refEq;
import static org.mockito.Mockito.*;

public class SampleTest {

    @Test
    public void test1() {
        // セットアップ
        Sample target = new Sample();
        Logic logic = mock(Logic.class);

        // テスト実行
        target.execute1(logic);

        // 結果検証
        verify(logic, times(1)).execute1(1); // OK
    }

    @Test
    public void test2() {
        // セットアップ
        Sample target = new Sample();
        Logic logic = mock(Logic.class);

        // テスト実行
        Dto dto = new Dto();
        dto.setNo(1);
        target.execute2(logic, dto);

        // 結果検証
        verify(logic, times(1)).execute2(dto); // OK
    }

    @Test
    public void test3() {
        // セットアップ
        Sample target = new Sample();
        Logic logic = mock(Logic.class);

        // テスト実行
        target.execute3(logic);

        // 結果検証
        Dto dto = new Dto();
        dto.setNo(1);
        verify(logic, times(1)).execute3(dto); // NG
        verify(logic, times(1)).execute3(refEq(dto)); // OK
    }

    @Test
    public void test4() {
        // セットアップ
        Sample target = new Sample();
        Logic logic = mock(Logic.class);

        // テスト実行
        target.execute4(logic);

        // 結果検証
        NestDto nestDto = new NestDto();
        nestDto.setDto(new Dto());
        nestDto.getDto().setNo(1);
        verify(logic, times(1)).execute4(refEq(nestDto)); // NG

        ArgumentMatcher<NestDto> matcher = argument -> {
            assertThat(argument.getDto().getNo(), is(1));
            return true;
        };
        verify(logic, times(1)).execute4(argThat(matcher)); // OK
    }

}

参考文献

javadoc.io