サーチ…


シンプルモック

Mockitoは、(最終的ではない)クラスとインターフェースのモックを作成するための、すべてのサイズのワンサイズのメッシュを提供します。

Dependency mock = Mockito.mock(Dependency.class);

これは、 Dependencyがインタフェースかクラスかにかかわらず、 Dependency模擬インスタンスを作成します。

その後、Mockito.when(x).thenReturn(y)表記法を使用して、そのモックへのメソッド呼び出しをスタブすることができます。

Mockito.when(mock.possiblyBuggyMethod()).thenReturn("someString");

したがって、 Dependency.possiblyBuggyMethod()呼び出しは単に"someString"返します。

タイプセーフではないため、ほとんどのユースケースでは推奨されない別の表記法があります。

Mockito.doReturn("someString").when(mock).possiblyBuggyMethod()

デフォルトのモック

シンプルモックはすべての呼び出しにnull(またはプリミティブのデフォルト)を返しますが、その動作を変更することは可能です。

Dependency mock = Mockito.mock(Dependency.class, new Answer() {

        @Override
        public Object answer(InvocationOnMock invocationOnMock) throws Throwable {
            return "someString";
        }
    });

またはラムダを使用して:

Dependency mock = Mockito.mock(Dependency.class, (Answer) invocationOnMock -> "someString");

この例では、すべての呼び出しに対して「someString」が返されますが、answer-methodで任意のロジックを定義することは可能です。

アノテーションを使用してクラスを非難する

テスト中のクラス:

public class GreetingsService { // class to be tested in isolation
    private UserService userService;

    public GreetingsService(UserService userService) {
        this.userService = userService;
    }

    public String getGreetings(int userId, LocalTime time) { // the method under test
        StringBuilder greetings = new StringBuilder();
        String timeOfDay = getTimeOfDay(time.getHour());
        greetings.append("Good ").append(timeOfDay).append(", ");
        greetings.append(userService.getFirstName(userId)) // this call will be mocked
                .append(" ")
                .append(userService.getLastName(userId)) // this call will be mocked
                .append("!");
        return greetings.toString();
    }

    private String getTimeOfDay(int hour) { // private method doesn't need to be unit tested
        if (hour >= 0 && hour < 12)
            return "Morning";
        else if (hour >= 12 && hour < 16)
            return "Afternoon";
        else if (hour >= 16 && hour < 21)
            return "Evening";
        else if (hour >= 21 && hour < 24)
            return "Night";
        else
            return null;
    }
}

このインタフェースの動作は嘲笑されます:

public interface UserService {
    String getFirstName(int userId);

    String getLastName(int userId);
}

UserService実際の実装を想定しUserService

public class UserServiceImpl implements UserService {
    @Override
    public String getFirstName(int userId) {
        String firstName = "";
        // some logic to get user's first name goes here
        // this could be anything like a call to another service,
        // a database query, or a web service call
        return firstName;
    }

    @Override
    public String getLastName(int userId) {
        String lastName = "";
        // some logic to get user's last name goes here
        // this could be anything like a call to another service,
        // a database query, or a web service call
        return lastName;
    }
}

MockitoのJunitテスト:

public class GreetingsServiceTest {
    @Mock
    private UserServiceImpl userService; // this class will be mocked
    @InjectMocks
    private GreetingsService greetingsService = new GreetingsService(userService);

    @Before
    public void setUp() {
        MockitoAnnotations.initMocks(this);
    }

    @Test
    public void testGetGreetings_morning() throws Exception {
        // specify mocked behavior
        when(userService.getFirstName(99)).thenReturn("John");
        when(userService.getLastName(99)).thenReturn("Doe");
        // invoke method under test
        String greetings = greetingsService.getGreetings(99, LocalTime.of(0, 45));
        Assert.assertEquals("Failed to get greetings!", "Good Morning, John Doe!", greetings);
    }

    @Test
    public void testGetGreetings_afternoon() throws Exception {
        // specify mocked behavior
        when(userService.getFirstName(11)).thenReturn("Jane");
        when(userService.getLastName(11)).thenReturn("Doe");
        // invoke method under test
        String greetings = greetingsService.getGreetings(11, LocalTime.of(13, 15));
        Assert.assertEquals("Failed to get greetings!", "Good Afternoon, Jane Doe!", greetings);
    }
}

部分的な嘲笑のための「スパイ」

@Spyアノテーション (またはメソッド )を使用して、オブジェクトを部分的にモックすることができます。これは、クラスの動作を部分的にモックする場合に便利です。たとえば、2つの異なるサービスを使用するクラスがあり、そのうちの1つだけを疑似し、他のサービスの実際の実装を使用するとします。

補足説明:哲学的には、実際のクラスを統合し、テスト対象のクラスを完全に分離してテストしないので、これを真の意味で「純粋な単体テスト」とは考えません。それにもかかわらず、これは現実世界で実際に有用であり、実際のDAOを使用できるようにメモリデータベースの実装を使用してデータベースをモックするときによく使用します。

Class under test:
public class GreetingsService { // class to be tested in isolation
    private UserService userService;
    private AppService appService;

    public GreetingsService(UserService userService, AppService appService) {
        this.userService = userService;
        this.appService = appService;
    }

    public String getGreetings(int userId, LocalTime time) { // the method under test
        StringBuilder greetings = new StringBuilder();
        String timeOfDay = getTimeOfDay(time.getHour());
        greetings.append("Good ").append(timeOfDay).append(", ");
        greetings.append(userService.getFirstName(userId)) // this call will be mocked
                .append(" ")
                .append(userService.getLastName(userId)) // this call will be mocked
                .append("!");
        greetings.append(" Welcome to ")
                .append(appService.getAppName()) // actual method call will be made
                .append(".");
        return greetings.toString();
    }

    private String getTimeOfDay(int hour) { // private method doesn't need to be unit tested
        if (hour >= 0 && hour < 12)
            return "Morning";
        else if (hour >= 12 && hour < 16)
            return "Afternoon";
        else if (hour >= 16 && hour < 21)
            return "Evening";
        else if (hour >= 21 && hour < 24)
            return "Night";
        else
            return null;
    }
}

このインタフェースの動作は嘲笑されます:

public interface UserService {
    String getFirstName(int userId);

    String getLastName(int userId);
}

UserService実際の実装を想定しUserService

public class UserServiceImpl implements UserService {
    @Override
    public String getFirstName(int userId) {
        String firstName = "";
        // some logic to get user's first name
        // this could be anything like a call to another service,
        // a database query, or a web service call
        return firstName;
    }

    @Override
    public String getLastName(int userId) {
        String lastName = "";
        // some logic to get user's last name
        // this could be anything like a call to another service,
        // a database query, or a web service call
        return lastName;
    }
}

このインタフェースの動作は嘲笑されません:

public interface AppService {
    String getAppName();
}

AppService実際の実装をAppServiceます:

public class AppServiceImpl implements AppService {
    @Override
    public String getAppName() {
        // assume you are reading this from properties file
        String appName = "The Amazing Application";
        return appName;
    }
}

MockitoのJunitテスト:

public class GreetingsServiceTest {
    @Mock
    private UserServiceImpl userService; // this class will be mocked
    @Spy
    private AppServiceImpl appService; // this class WON'T be mocked
    @InjectMocks
    private GreetingsService greetingsService = new GreetingsService(userService, appService);

    @Before
    public void setUp() {
        MockitoAnnotations.initMocks(this);
    }

    @Test
    public void testGetGreetings_morning() throws Exception {
        // specify mocked behavior
        when(userService.getFirstName(99)).thenReturn("John");
        when(userService.getLastName(99)).thenReturn("Doe");
        // invoke method under test
        String greetings = greetingsService.getGreetings(99, LocalTime.of(0, 45));
        Assert.assertEquals("Failed to get greetings!", "Good Morning, John Doe! Welcome to The Amazing Application.", greetings);
    }

    @Test
    public void testGetGreetings_afternoon() throws Exception {
        // specify mocked behavior
        when(userService.getFirstName(11)).thenReturn("Jane");
        when(userService.getLastName(11)).thenReturn("Doe");
        // invoke method under test
        String greetings = greetingsService.getGreetings(11, LocalTime.of(13, 15));
        Assert.assertEquals("Failed to get greetings!", "Good Afternoon, Jane Doe! Welcome to The Amazing Application.", greetings);
    }
}

モックされたオブジェクトにプライベートフィールドを設定する

テスト中のクラスでは、コンストラクタを経由してもアクセスできないプライベートフィールドがあるかもしれません。このような場合は、リフレクションを使用してそのようなプロパティを設定できます。これは、このようなJUnitテストのスニペットです。

@InjectMocks
private GreetingsService greetingsService = new GreetingsService(); // mocking this class

@Before
public void setUp() {
    MockitoAnnotations.initMocks(this);
    String someName = "Some Name";
    ReflectionTestUtils.setField(greetingsService, // inject into this object
        "name", // assign to this field
        someName); // object to be injected
}

ここではSptringのReflectionTestUtils.setField(Object targetObject, String name, Object value) メソッドを使用して簡素化していますが、これを行うには古いJava Reflectionを使用することができます。



Modified text is an extract of the original Stack Overflow Documentation
ライセンスを受けた CC BY-SA 3.0
所属していない Stack Overflow