当前位置: 首页 > 工具软件 > Mockito > 使用案例 >

[Mockito]

谷泽宇
2023-12-01

what is mocking?

Mocking is a way to test the functionality of a class in isolation. Mocking does not require a database connection or properties file read or file server read to test a functionality. Mock objects do the mocking of the real service. A mock object returns a dummy data corresponding to some dummy input passed to it.

Mock 测试就是在测试过程中,对于某些不容易构造(如 HttpServletRequest 必须在Servlet 容器中才能构造出来)或者不容易获取比较复杂的对象(如 JDBC 中的ResultSet 对象),用一个虚拟的对象(Mock 对象)来创建以便测试的测试方法。

quick start

业务代码:

@Getter
@Setter
public class Account {

    private String username;
    private String password;
}
public class AccountDao {
    public Account findAccount(String username, String password) {
        throw new UnsupportedOperationException();
    }
}
public class LoginController {

    private AccountDao accountDao;

    public LoginController(AccountDao accountDao) {
        this.accountDao = accountDao;
    }

    public String login(HttpServletRequest request) {

        String username = request.getParameter("username");
        String password = request.getParameter("password");
        try {

            Account account = accountDao.findAccount(username, password);
            if (account == null)
                return "/login";
        } catch (Exception e) {
            return "/505";
        }
        return "/index";
    }
}

单元测试:

public class LoginControllerTest {

    private AccountDao accountDao;
    private HttpServletRequest request;
    private LoginController loginController;

    @Before
    public void before() throws Exception {
        accountDao = Mockito.mock(AccountDao.class);
        request = Mockito.mock(HttpServletRequest.class);
        loginController = new LoginController(accountDao);
    }

    @After
    public void after() throws Exception {

    }

    /**
     * Method: login(HttpServletRequest request)
     */
    @Test
    public void testLoginSuccess() throws Exception {
        when(request.getParameter("username")).thenReturn("jimGreen");
        when(request.getParameter("password")).thenReturn("123456");
        when(accountDao.findAccount(anyString(), anyString())).thenReturn(new Account());

        assertThat(loginController.login(request), equalTo("/index"));
    }

    @Test
    public void testLoginFail() throws Exception {
        when(request.getParameter("username")).thenReturn("jimGreen");
        when(request.getParameter("password")).thenReturn("123456xx");
        when(accountDao.findAccount(anyString(), anyString())).thenReturn(null);

        assertThat(loginController.login(request), equalTo("/login"));
    }

    @Test
    public void testLoginException() throws Exception {
        when(request.getParameter("username")).thenReturn("jimGreen");
        when(request.getParameter("password")).thenReturn("123456xx");
        when(accountDao.findAccount(anyString(), anyString())).thenThrow(new UnsupportedOperationException());

        assertThat(loginController.login(request), equalTo("/505"));
    }
} 

说明

用到的业务代码示例:
domain:


mock

第一种方式:使用Runner的方式

@RunWith(MockitoJUnitRunner.class)
public class MockByRunner {

    private AccountDao accountDao;

    @Test
    public void testMock(){
        accountDao = mock(AccountDao.class, Mockito.RETURNS_SMART_NULLS);
        Account account = accountDao.findAccount("x", "x");
        System.out.println(account);
    }
}

第二种方式:使用Annotation的方式

public class MockByAnnotation {

    @Mock(answer = Answers.RETURNS_SMART_NULLS)
    AccountDao accountDao;

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

    @Test
    public void testMockByAnnotation() {
        Account account = accountDao.findAccount("x", "x");
        System.out.println(account);
    }

}

第三种方式:使用Rule的方式

public class MockByMockRule {

    @Rule
    public MockitoRule rule = MockitoJUnit.rule();

    @Mock(answer = Answers.RETURNS_SMART_NULLS)
    private AccountDao dao;

    @Test
    public void testMockRule(){
        Account account = dao.findAccount("x", "x");
        System.out.println(account);
    }

}

DeepMock

public class DeepMock {

    @Mock(answer = Answers.RETURNS_DEEP_STUBS)
    private Lession03Service service;

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

    @Test
    public void testDeepMock(){
        Lession03 lession03 = service.get();
        lession03.foo();
    }
}

spy

@RunWith(MockitoJUnitRunner.class)
public class SpyingTest {

    @Test
    public void testSpy() {
        List<String> realList = new ArrayList<>();
        List<String> list = spy(realList);

        list.add("mockito");
        list.add("powermock");

        assertThat(list.get(0), equalTo("mockito"));
        assertThat(list.get(1), equalTo("powermock"));
        assertThat(list.size(), equalTo(2));
        assertThat(list.isEmpty(), equalTo(false));

        when(list.isEmpty()).thenReturn(true);

        assertThat(list.get(0), equalTo("mockito"));
        assertThat(list.get(1), equalTo("powermock"));
        assertThat(list.size(), equalTo(2));
        assertThat(list.isEmpty(), equalTo(true));
    }
}

使用annotation进行spy

public class SpyingAnnotation {

    @Spy
    private List<String> list = new ArrayList<>();

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

    @Test
    public void testSpyingWithAnnotation(){
        list.add("mockito");
        list.add("powermock");

        assertThat(list.get(0), equalTo("mockito"));
        assertThat(list.get(1), equalTo("powermock"));
        assertThat(list.isEmpty(), equalTo(false));

        when(list.isEmpty()).thenReturn(true);
        when(list.size()).thenReturn(0);

        assertThat(list.get(0), equalTo("mockito"));
        assertThat(list.get(1), equalTo("powermock"));
        assertThat(list.isEmpty(), equalTo(true));
        assertThat(list.size(), equalTo(0));
    }

}

stubbing

业务代码:

public class StubbingService {

    public int getI(){
        System.out.println("=====getI=====");
        return 10;
    }

    public String getS(){
        System.out.println("=====getS=====");
        throw new RuntimeException();
    }

}

单元测试:

public class StubbingTest {

    private List<String> list;

    @Before
    public void before() {
        list = Mockito.mock(ArrayList.class);
    }

    @Test
    public void howToUseStubbing() {
        when(list.get(0)).thenReturn("first");
        assertThat(list.get(0), equalTo("first"));

        when(list.get(anyInt())).thenThrow(RuntimeException.class);
        try {
            list.get(0);
            fail();
        } catch (Exception e) {
            assertThat(e, instanceOf(RuntimeException.class));
        }

    }

    @Test
    public void howToStubbingVoidMethod() {
        Mockito.doNothing().when(list).clear();
        list.clear();
        verify(list, times(1)).clear();

        doThrow(RuntimeException.class).when(list).clear();
        try {
            list.clear();
            fail();
        } catch (Exception e) {
            assertThat(e, instanceOf(RuntimeException.class));
        }
    }

    @Test
    public void stubbingDoReturn() {
        when(list.get(0)).thenReturn("first");
        doReturn("second").when(list).get(1);

        assertThat(list.get(0), equalTo("first"));
        assertThat(list.get(1), equalTo("second"));
    }

    @Test
    public void iterateStubbing() {
//        when(list.size()).thenReturn(1,2,3,4);
        when(list.size()).thenReturn(1).thenReturn(2).thenReturn(3).thenReturn(4);

        assertThat(list.size(), equalTo(1));
        assertThat(list.size(), equalTo(2));
        assertThat(list.size(), equalTo(3));
        assertThat(list.size(), equalTo(4));
        assertThat(list.size(), equalTo(4));
    }

    @Test
    public void stubbingWithAnswer() {
        when(list.get(anyInt())).thenAnswer(invocationOnMock -> {
            Integer index = invocationOnMock.getArgumentAt(0, Integer.class);
            return String.valueOf(index * 10);
        });
        assertThat(list.get(0), equalTo("0"));
        assertThat(list.get(99), equalTo("990"));
    }

    @Test
    public void stubbingWithRealCall() {
        StubbingService service = mock(StubbingService.class);
        when(service.getS()).thenReturn("hello");
        when(service.getI()).thenCallRealMethod();

        assertThat(service.getS(), equalTo("hello"));
        assertThat(service.getI(), equalTo(10));
    }

    @After
    public void after() {
        Mockito.reset(this.list);
    }

}

argument Matcher

public class ArgumentMatcherTest {

    @Test
    public void testBasic() {
        List<Integer> list = mock(ArrayList.class);

        when(list.get(0)).thenReturn(100);

        assertThat(list.get(0), equalTo(100));
        assertThat(list.get(1), nullValue());
    }

    @Test
    public void testComplex() {

        Foo foo = mock(Foo.class);
        when(foo.function(Mockito.isA(Parent.class))).thenReturn(100);

        assertThat(foo.function(new Child1()), equalTo(100));
        assertThat(foo.function(new Child2()), equalTo(100));

        reset(foo);

        when(foo.function(Mockito.any(Child1.class))).thenReturn(100);
        assertThat(foo.function(new Child2()), equalTo(100));

    }

    static class Foo {
        int function(Parent p) {
            return p.work();
        }
    }

    interface Parent {
        int work();
    }

    static class Child1 implements Parent {

        @Override
        public int work() {
            throw new RuntimeException();
        }
    }

    static class Child2 implements Parent {

        @Override
        public int work() {
            throw new RuntimeException();
        }
    }

}

verify


@RunWith(MockitoJUnitRunner.class)
public class VerifyTest {

    @Mock
    private UserDao userDao;

    @Test
    public void testCallCreateuser() {
        UserService userService = new UserService(userDao);
        User user = new User("123456");
        when(userDao.isExist(user)).thenReturn(false);
        when(userDao.create(user)).thenReturn(true);
        when(userDao.update(user)).thenReturn(true);

        boolean result = userService.merge(user);
        assertThat(result, equalTo(true));
        verify(userDao, times(0)).update(user);
        verify(userDao, times(1)).create(user);
    }

    @Test
    public void testCallUpdateuser() {
        UserService UserService = new UserService(userDao);
        User user = new User("123456");
        when(userDao.isExist(user)).thenReturn(true);
        when(userDao.create(user)).thenReturn(true);
        when(userDao.update(user)).thenReturn(true);

        boolean result = UserService.merge(user);
        assertThat(result, equalTo(true));
        verify(userDao, times(1)).update(user);
        verify(userDao, times(0)).create(user);
    }

    @Test
    public void testMerge() {
        UserService UserService = new UserService(userDao);
        User user = new User("123456");
        when(userDao.isExist(user)).thenReturn(false, true);
        when(userDao.create(user)).thenReturn(true);
        when(userDao.update(user)).thenReturn(true);

        boolean result = UserService.merge(user);
        assertThat(result, equalTo(true));
        verify(userDao, times(0)).update(user);
        verify(userDao, times(1)).create(user);

        result = UserService.merge(user);
        assertThat(result, equalTo(true));
        verify(userDao, times(1)).update(user);
        verify(userDao, times(1)).create(user);
    }

    @After
    public void after() {
        reset(userDao);
    }

}

argument Captor

@RunWith(MockitoJUnitRunner.class)
public class ArgumentCaptorTest {

    @Mock
    private List<String> list;

    @Mock
    private UserDao userDao;

    @Test
    public void test() {
        ArgumentCaptor<String> captor = ArgumentCaptor.forClass(String.class);

        when(list.add("mockito")).thenReturn(true);
        list.add("mockito");

        verify(list, times(1)).add("mockito");
        verify(list, times(1)).add(captor.capture());
        assertThat(captor.getValue(), equalTo("mockito"));
    }

    @Test
    public void test2() {
        UserService userService = new UserService(userDao);

        User user = new User("123456");
        when(userDao.delete(user)).thenReturn(true);

        assertThat(userService.deleteUser(user), equalTo(true));
        assertThat(user.getType(), equalTo("D"));
        ArgumentCaptor<User> captor = ArgumentCaptor.forClass(User.class);
        verify(userDao, times(1)).delete(captor.capture());
    }

}
 类似资料: