赞
踩
目录
三.快速开始 quickstart
八.WORKING WITH WILDCARD MATCHERS
Mock 测试就是在测试过程中,对于某些不容易构造(如 HttpServletRequest 必须在Servlet 容器中才能构造出来)或者不容易获取比较复杂的对象(如 JDBC 中的ResultSet 对象),用一个虚拟的对象(Mock 对象)来创建以便测试的测试方法。
Mock 最大的功能是帮你把单元测试的耦合分解开,如果你的代码对另一个类或者接口有依赖,它能够帮你模拟这些依赖,并帮你验证所调用的依赖的行为。
一段代码有这样的依赖:
当我们需要测试A类的时候,如果没有 Mock,则我们需要把整个依赖树都构建出来,而使用 Mock 的话就可以将结构分解开,像下面这样:
真实对象具有不可确定的行为,产生不可预测的效果(如:股票行情,天气预报) :
Mockito 是一个强大的用于 Java 开发的模拟测试框架, 通过 Mockito 我们可以创建和配置 Mock 对象, 进而简化有外部依赖的类的测试.
使用 Mockito 的大致流程如下:
创建外部依赖的 Mock 对象, 然后将此 Mock 对象注入到测试类中.
执行测试代码.
校验测试代码是否执行正确.
1.maven 依赖
- <dependency>
- <groupId>org.mockito</groupId>
- <artifactId>mockito-all</artifactId>
- <version>1.10.19</version>
- <scope>test</scope>
- </dependency>
引入相关依赖
- <dependencies>
- <dependency>
- <groupId>junit</groupId>
- <artifactId>junit</artifactId>
- <version>4.12</version>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>org.mockito</groupId>
- <artifactId>mockito-all</artifactId>
- <version>1.10.19</version>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>javax.servlet</groupId>
- <artifactId>javax.servlet-api</artifactId>
- <version>3.1.0</version>
- <scope>provided</scope>
- </dependency>
- </dependencies>
common部分代码
AccountLoginController.java
- package com.wangwenjun.mockito.common;
-
- import javax.servlet.http.HttpServletRequest;
-
- public class AccountLoginController
- {
-
- private final AccountDao accountDao;
-
- public AccountLoginController(AccountDao accountDao)
- {
- this.accountDao = accountDao;
- }
-
- public String login(HttpServletRequest request)
- {
-
- final String userName = request.getParameter("username");
- final String password = request.getParameter("password");
- try
- {
- Account account = accountDao.findAccount(userName, password);
- if (account == null)
- {
- return "/login";
- } else
- {
- return "/index";
- }
- } catch (Exception e)
- {
- return "/505";
- }
- }
- }
AccountDao.java
- package com.wangwenjun.mockito.common;
-
- public class AccountDao
- {
-
- public Account findAccount(String username, String password)
- {
- throw new UnsupportedOperationException();
- }
- }
Account.java
- package com.wangwenjun.mockito.common;
-
- public class Account
- {
- }
AccountLoginControllerTest.java
- package com.wangwenjun.mockito.quickstart;
-
- import com.wangwenjun.mockito.common.Account;
- import com.wangwenjun.mockito.common.AccountDao;
- import com.wangwenjun.mockito.common.AccountLoginController;
- import org.junit.Before;
- import org.junit.Test;
- import org.junit.runner.RunWith;
- import org.mockito.Mockito;
- import org.mockito.runners.MockitoJUnitRunner;
-
- import javax.servlet.http.HttpServletRequest;
-
- import static org.hamcrest.CoreMatchers.equalTo;
- import static org.junit.Assert.assertThat;
- import static org.mockito.Matchers.anyString;
- import static org.mockito.Mockito.when;
-
- @RunWith(MockitoJUnitRunner.class)
- public class AccountLoginControllerTest
- {
-
- private AccountDao accountDao;
-
- private HttpServletRequest request;
-
- private AccountLoginController accountLoginController;
-
- @Before
- public void setUp()
- {
- this.accountDao = Mockito.mock(AccountDao.class);
- this.request = Mockito.mock(HttpServletRequest.class);
- this.accountLoginController = new AccountLoginController(accountDao);
- }
-
- @Test
- public void testLoginSuccess()
- {
- Account account = new Account();
- when(request.getParameter("username")).thenReturn("alex");
- when(request.getParameter("password")).thenReturn("123456");
- when(accountDao.findAccount(anyString(), anyString())).thenReturn(account);
-
- assertThat(accountLoginController.login(request), equalTo("/index"));
-
- }
-
- @Test
- public void testLoginFailure()
- {
- when(request.getParameter("username")).thenReturn("alex");
- when(request.getParameter("password")).thenReturn("1234561");
- when(accountDao.findAccount(anyString(), anyString())).thenReturn(null);
-
- assertThat(accountLoginController.login(request), equalTo("/login"));
- }
-
- @Test
- public void testLogin505()
- {
- when(request.getParameter("username")).thenReturn("alex");
- when(request.getParameter("password")).thenReturn("1234561");
- when(accountDao.findAccount(anyString(), anyString())).thenThrow(UnsupportedOperationException.class);
- assertThat(accountLoginController.login(request), equalTo("/505"));
- }
- }
分析:
1.
@RunWith(MockitoJUnitRunner.class)
@RunWith(MockitoJUnitRunner.class)就是指用MockitoJUnitRunner来运行
2.模拟对象
创建 Mock 对象的语法为 mock(class or interface)。
- @Before
- public void setUp()
- {
- this.accountDao = Mockito.mock(AccountDao.class);
- this.request = Mockito.mock(HttpServletRequest.class);
- this.accountLoginController = new AccountLoginController(accountDao);
- }
简单的理解:通过mock 模拟accountLoginController 的对象,拥有accountLoginController 的所有方法和属性 但并不是new 了一个而是伪装了一个该对象
when(mock.someMethod()).thenReturn(value)
设定 Mock 对象某个方法调用时的返回值
- when(request.getParameter("username")).thenReturn("alex");
- when(request.getParameter("password")).thenReturn("123456");
- when(accountDao.findAccount(anyString(), anyString())).thenReturn(account);
stubbing的相关行为:
3.播放
将录制的结果播放,同时通过断言的方式判断结果
assertThat(accountLoginController.login(request), equalTo("/index"));
1.
@RunWith(MockitoJUnitRunner.class) 和AccountDao accountDao = mock(AccountDao.class, Mockito.RETURNS_SMART_NULLS); 方式
- @RunWith(MockitoJUnitRunner.class)
- public class MockByRunnerTest
- {
-
- @Test
- public void testMock()
- {
- AccountDao accountDao = mock(AccountDao.class, Mockito.RETURNS_SMART_NULLS);
- Account account = accountDao.findAccount("x", "x");
- System.out.println(account);
- }
- }
2.MockitoAnnotations.initMocks(this);和@Mock的方式来构建
- package com.wangwenjun.mockito.lesson03;
-
- import com.wangwenjun.mockito.common.Account;
- import com.wangwenjun.mockito.common.AccountDao;
- import org.junit.Before;
- import org.junit.Test;
- import org.mockito.Answers;
- import org.mockito.Mock;
- import org.mockito.MockitoAnnotations;
-
- public class MockByAnnotationTest
- {
-
- @Before
- public void init()
- {
- MockitoAnnotations.initMocks(this);
- }
-
- @Mock(answer = Answers.RETURNS_SMART_NULLS)
- private AccountDao accountDao;
-
- @Test
- public void testMock()
- {
- Account account = accountDao.findAccount("x", "x");
- System.out.println(account);
- }
- }
3. 由于@RunWith 只能加载一个,当使用junit时候 就不能加载mokcito运行器
- @Rule
- public MockitoRule mockitoRule = MockitoJUnit.rule();
-
- @Mock
- private AccountDao accountDao;
方式进行mock
- package com.wangwenjun.mockito.lesson03;
-
- import com.wangwenjun.mockito.common.Account;
- import com.wangwenjun.mockito.common.AccountDao;
- import org.junit.Rule;
- import org.junit.Test;
- import org.mockito.Answers;
- import org.mockito.Mock;
- import org.mockito.junit.MockitoJUnit;
- import org.mockito.junit.MockitoRule;
-
- public class MockByRuleTest
- {
-
- @Rule
- public MockitoRule mockitoRule = MockitoJUnit.rule();
-
- @Mock
- private AccountDao accountDao;
-
- @Test
- public void testMock()
- {
- // AccountDao dao = mock(AccountDao.class);
- Account account = accountDao.findAccount("x", "x");
- System.out.println(account);
- }
- }
了解:mock一个对象时候,能够更改默认值(待深入研究,此处只做相关提醒)
https://blog.csdn.net/dnc8371/article/details/106706971
RETURNS_DEEP_STUBS
RETURNS_MOCKS
when(mock.someMethod()).thenReturn(value)
例子1:
when(mock.someMethod()).thenReturn(value) 来设定 Mock 对象某个方法调用时的返回值
when(mock.someMethod()).thenThrow(new RuntimeException) 的方式来设定当调用某个方法时抛出的异常
- @Test
- public void howToUseStubbing()
- {
- when(list.get(0)).thenReturn("first");
- assertThat(list.get(0), equalTo("first"));
-
- when(list.get(anyInt())).thenThrow(new RuntimeException());
- try
- {
- list.get(0);
- fail();
- } catch (Exception e)
- {
- assertThat(e, instanceOf(RuntimeException.class));
- }
- }
2.void类型的函数 howToStubbingVoidMethod
使用 doNothing().when(list).clear(); 的方式Mock没有返回值类型的函数
使用 doThrow(RuntimeException.class).when(list).clear(); 的方式Mock没有返回值类型的函数
- @Test
- public void howToStubbingVoidMethod()
- {
- 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));
- }
- }
3.doReturn("second").when(list).get(1);
的相关写法
- @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"));
- }
4. iterateSubbing Stubbing的迭代写法、
第五次还是4
- @Test
- public void iterateSubbing()
- {
- 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));
- }
运行结果
5.stubbingWithAnswer
Answer 是个泛型接口。
到调用发生时将执行这个回调,通过 Object[] args = invocation.getArguments();可以拿到调用时传入的参数,
通过 Object mock = invocation.getMock();可以拿到mock对象。
有些方法可能接口的参数为一个Listener参数,如果我们使用Answer打桩,我们就可以获取这个Listener,并且在Answer函数中执行对应的回调函数
,这对我们了解函数的内部执行过成有很大的帮助。
- @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(999), equalTo("9990"));
- }
6.stubbingWithRealCall
mock出来的对象并不会真正的去执行,而该函数将会真正执行mock对象的那个方法
- @Test
- public void stubbingWithRealCall()
- {
- StubbingService service = mock(StubbingService.class);
- // when(service.getS()).thenReturn("Alex");
- // assertThat(service.getS(), equalTo("Alex"));
-
- when(service.getI()).thenCallRealMethod();
- assertThat(service.getI(), equalTo(10));
- }
你可以为真实对象创建一个监控(spy)对象,当你使用这个spy对象时,真实的对象也会被调用,除非它的函数被打桩。你应该尽量少的使用spy对象,使用时也需要小心,例如spy对象可以用来处理遗留代码,Spy示例如下:
mock部分的方法
- package com.wangwenjun.mockito.lesson06;
-
- import org.junit.Test;
- import org.junit.runner.RunWith;
- import org.mockito.runners.MockitoJUnitRunner;
-
- import java.util.ArrayList;
- import java.util.List;
-
- import static org.hamcrest.CoreMatchers.equalTo;
- import static org.junit.Assert.assertThat;
- import static org.mockito.Mockito.spy;
- import static org.mockito.Mockito.when;
-
- @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.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));
- }
- }
@Spy 注解的方式实现spy
- package com.wangwenjun.mockito.lesson06;
-
- import org.junit.Before;
- import org.junit.Test;
- import org.mockito.MockitoAnnotations;
- import org.mockito.Spy;
-
- import java.util.ArrayList;
- import java.util.List;
-
- import static org.hamcrest.CoreMatchers.equalTo;
- import static org.junit.Assert.assertThat;
- import static org.mockito.Mockito.when;
-
- public class SpyingAnnotationTest
- {
-
- @Spy
- private List<String> list = new ArrayList<>();
-
- @Before
- public void init()
- {
- MockitoAnnotations.initMocks(this);
- }
-
- @Test
- public void testSpy()
- {
- 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));
- }
- }
any() 任意入参,经过语法检查的都会生效
isA() 必须是该实例 该录制将会生效
- package com.wangwenjun.mockito.lesson07;
-
- import org.junit.Test;
- import org.mockito.Mockito;
-
- import java.util.ArrayList;
- import java.util.List;
-
- import static org.hamcrest.CoreMatchers.equalTo;
- import static org.hamcrest.CoreMatchers.nullValue;
- import static org.junit.Assert.assertThat;
- import static org.mockito.Mockito.*;
-
- public class ArgumentsMatcherTest
- {
- @Test
- public void basicTest()
- {
- List<Integer> list = mock(ArrayList.class);
-
- when(list.get(eq(0))).thenReturn(100);
- assertThat(list.get(0), equalTo(100));
- assertThat(list.get(1), nullValue());
- }
-
- /*isA, any*/
- @Test
- public void testComplex()
- {
- Foo foo = mock(Foo.class);
- when(foo.function(Mockito.isA(Child1.class))).thenReturn(100);
- int result = foo.function(new Child1());
- assertThat(result, equalTo(100));
-
- result = foo.function(new Child2());
- assertThat(result, equalTo(0));
-
- reset(foo);
-
- when(foo.function(Mockito.any(Child1.class))).thenReturn(100);
- result = foo.function(new Child2());
- assertThat(result, equalTo(100));
- }
-
- static class Foo
- {
- int function(Parent p)
- {
- return p.work();
- }
- }
-
- interface Parent
- {
- int work();
- }
-
- class Child1 implements Parent
- {
-
- @Override
- public int work()
- {
- throw new RuntimeException();
- }
- }
-
- class Child2 implements Parent
- {
-
- @Override
- public int work()
- {
- throw new RuntimeException();
- }
- }
-
- }
anyXXX()
any()
isA()
例子:
- package com.wangwenjun.mockito.lesson08;
-
-
- import org.junit.After;
- import org.junit.Test;
- import org.junit.runner.RunWith;
- import org.mockito.Mock;
- import org.mockito.runners.MockitoJUnitRunner;
-
- import java.io.Serializable;
- import java.util.Collections;
- import java.util.List;
-
- import static org.hamcrest.CoreMatchers.equalTo;
- import static org.junit.Assert.assertThat;
- import static org.mockito.Matchers.anyCollection;
- import static org.mockito.Mockito.*;
-
- @RunWith(MockitoJUnitRunner.class)
- public class WildcardArgumentMatcherTest
- {
-
- @Mock
- private SimpleService simpleService;
-
- @Test
- public void wildcardMethod1()
- {
- when(simpleService.method1(anyInt(), anyString(), anyCollection(), isA(Serializable.class))).thenReturn(100);
- int result = simpleService.method1(1, "Alex", Collections.emptyList(), "Mockito");
- assertThat(result, equalTo(100));
-
- result = simpleService.method1(1, "Wang", Collections.emptySet(), "MockitoForJava");
- assertThat(result, equalTo(100));
- }
-
- @Test
- public void wildcardMethod1WithSpec()
- {
- when(simpleService.method1(anyInt(), anyString(), anyCollection(), isA(Serializable.class))).thenReturn(-1);
- when(simpleService.method1(anyInt(), eq("Alex"), anyCollection(), isA(Serializable.class))).thenReturn(100);
- when(simpleService.method1(anyInt(), eq("Wang"), anyCollection(), isA(Serializable.class))).thenReturn(200);
-
-
- int result = simpleService.method1(1, "Alex", Collections.emptyList(), "Mockito");
- assertThat(result, equalTo(100));
-
- result = simpleService.method1(1, "Wang", Collections.emptyList(), "Mockito");
- assertThat(result, equalTo(200));
-
- result = simpleService.method1(1, "sfsfs", Collections.emptyList(), "Mockito");
- assertThat(result, equalTo(-1));
- }
-
-
- @Test
- public void wildcardMethod2()
- {
- List<Object> emptyList = Collections.emptyList();
- doNothing().when(simpleService).method2(anyInt(), anyString(), anyCollection(), isA(Serializable.class));
- simpleService.method2(1, "Alex", emptyList, "Mockito");
- verify(simpleService, times(1)).method2(1, "Alex", emptyList, "Mockito");
- verify(simpleService, times(1)).method2(anyInt(), eq("Alex"), anyCollection(), isA(Serializable.class));
-
- }
-
- @After
- public void destroy()
- {
- reset(simpleService);
- }
- }
默认验证的是执行了times(1),也就是某个测试函数是否执行了1次.因此,times(1)通常被省略了。
- @Test
- public void tesVerify()
- {
- List mockedList = mock(List.class);
-
- mockedList.add("once");
-
- mockedList.add("twice");
- mockedList.add("twice");
-
- mockedList.add("three times");
- mockedList.add("three times");
- mockedList.add("three times");
-
- //following two verifications work exactly the same - times(1) is used by default
- // 下面的两个验证函数效果一样,因为verify默认验证的就是times(1)
- verify(mockedList).add("once");
- verify(mockedList, times(1)).add("once");
-
- //exact number of invocations verification
- // 验证具体的执行次数
- verify(mockedList, times(2)).add("twice");
- verify(mockedList, times(3)).add("three times");
-
- //verification using never(). never() is an alias to times(0)
- // 使用never()进行验证,never相当于times(0)
- verify(mockedList, never()).add("never happened");
-
- //verification using atLeast()/atMost()
- // 使用atLeast()/atMost()
- verify(mockedList, atLeastOnce()).add("three times");
- // verify(mockedList, atLeast(2)).add("five times");
- verify(mockedList, atMost(5)).add("three times");
-
-
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。