当前位置:   article > 正文

单元测试(三) mockito入门_mockitojunitrunner

mockitojunitrunner

目录

 

一.什么是mock测试

二.什么是Mockito

三.快速开始 quickstart

四.3种不同的mock方式 

五. Stubbing

六.spying

七.Mockito Argument Matchers

八.WORKING WITH WILDCARD MATCHERS

九.verify函数


 

 

 

 

一.什么是mock测试

 

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

Mock 最大的功能是帮你把单元测试的耦合分解开,如果你的代码对另一个类或者接口有依赖,它能够帮你模拟这些依赖,并帮你验证所调用的依赖的行为。

 

一段代码有这样的依赖:

 

当我们需要测试A类的时候,如果没有 Mock,则我们需要把整个依赖树都构建出来,而使用 Mock 的话就可以将结构分解开,像下面这样:

 

Mock 对象使用范畴

真实对象具有不可确定的行为,产生不可预测的效果(如:股票行情,天气预报) :

  • 真实对象很难被创建的
  • 真实对象的某些行为很难被触发
  • 真实对象实际上还不存在的(和其他开发小组或者和新的硬件打交道)等等

二.什么是Mockito

 

Mockito 是一个强大的用于 Java 开发的模拟测试框架, 通过 Mockito 我们可以创建和配置 Mock 对象, 进而简化有外部依赖的类的测试.
使用 Mockito 的大致流程如下:

  • 创建外部依赖的 Mock 对象, 然后将此 Mock 对象注入到测试类中.

  • 执行测试代码.

  • 校验测试代码是否执行正确.

三.快速开始 quickstart

1.maven 依赖

    

  1. <dependency>
  2. <groupId>org.mockito</groupId>
  3. <artifactId>mockito-all</artifactId>
  4. <version>1.10.19</version>
  5. <scope>test</scope>
  6. </dependency>

引入相关依赖

 

  1. <dependencies>
  2. <dependency>
  3. <groupId>junit</groupId>
  4. <artifactId>junit</artifactId>
  5. <version>4.12</version>
  6. <scope>test</scope>
  7. </dependency>
  8. <dependency>
  9. <groupId>org.mockito</groupId>
  10. <artifactId>mockito-all</artifactId>
  11. <version>1.10.19</version>
  12. <scope>test</scope>
  13. </dependency>
  14. <dependency>
  15. <groupId>javax.servlet</groupId>
  16. <artifactId>javax.servlet-api</artifactId>
  17. <version>3.1.0</version>
  18. <scope>provided</scope>
  19. </dependency>
  20. </dependencies>

common部分代码

 

AccountLoginController.java
  1. package com.wangwenjun.mockito.common;
  2. import javax.servlet.http.HttpServletRequest;
  3. public class AccountLoginController
  4. {
  5. private final AccountDao accountDao;
  6. public AccountLoginController(AccountDao accountDao)
  7. {
  8. this.accountDao = accountDao;
  9. }
  10. public String login(HttpServletRequest request)
  11. {
  12. final String userName = request.getParameter("username");
  13. final String password = request.getParameter("password");
  14. try
  15. {
  16. Account account = accountDao.findAccount(userName, password);
  17. if (account == null)
  18. {
  19. return "/login";
  20. } else
  21. {
  22. return "/index";
  23. }
  24. } catch (Exception e)
  25. {
  26. return "/505";
  27. }
  28. }
  29. }
AccountDao.java
  1. package com.wangwenjun.mockito.common;
  2. public class AccountDao
  3. {
  4. public Account findAccount(String username, String password)
  5. {
  6. throw new UnsupportedOperationException();
  7. }
  8. }
Account.java
  1. package com.wangwenjun.mockito.common;
  2. public class Account
  3. {
  4. }
AccountLoginControllerTest.java
  1. package com.wangwenjun.mockito.quickstart;
  2. import com.wangwenjun.mockito.common.Account;
  3. import com.wangwenjun.mockito.common.AccountDao;
  4. import com.wangwenjun.mockito.common.AccountLoginController;
  5. import org.junit.Before;
  6. import org.junit.Test;
  7. import org.junit.runner.RunWith;
  8. import org.mockito.Mockito;
  9. import org.mockito.runners.MockitoJUnitRunner;
  10. import javax.servlet.http.HttpServletRequest;
  11. import static org.hamcrest.CoreMatchers.equalTo;
  12. import static org.junit.Assert.assertThat;
  13. import static org.mockito.Matchers.anyString;
  14. import static org.mockito.Mockito.when;
  15. @RunWith(MockitoJUnitRunner.class)
  16. public class AccountLoginControllerTest
  17. {
  18. private AccountDao accountDao;
  19. private HttpServletRequest request;
  20. private AccountLoginController accountLoginController;
  21. @Before
  22. public void setUp()
  23. {
  24. this.accountDao = Mockito.mock(AccountDao.class);
  25. this.request = Mockito.mock(HttpServletRequest.class);
  26. this.accountLoginController = new AccountLoginController(accountDao);
  27. }
  28. @Test
  29. public void testLoginSuccess()
  30. {
  31. Account account = new Account();
  32. when(request.getParameter("username")).thenReturn("alex");
  33. when(request.getParameter("password")).thenReturn("123456");
  34. when(accountDao.findAccount(anyString(), anyString())).thenReturn(account);
  35. assertThat(accountLoginController.login(request), equalTo("/index"));
  36. }
  37. @Test
  38. public void testLoginFailure()
  39. {
  40. when(request.getParameter("username")).thenReturn("alex");
  41. when(request.getParameter("password")).thenReturn("1234561");
  42. when(accountDao.findAccount(anyString(), anyString())).thenReturn(null);
  43. assertThat(accountLoginController.login(request), equalTo("/login"));
  44. }
  45. @Test
  46. public void testLogin505()
  47. {
  48. when(request.getParameter("username")).thenReturn("alex");
  49. when(request.getParameter("password")).thenReturn("1234561");
  50. when(accountDao.findAccount(anyString(), anyString())).thenThrow(UnsupportedOperationException.class);
  51. assertThat(accountLoginController.login(request), equalTo("/505"));
  52. }
  53. }

 

分析:

1.

@RunWith(MockitoJUnitRunner.class)

@RunWith(MockitoJUnitRunner.class)就是指用MockitoJUnitRunner来运行

2.模拟对象

创建 Mock 对象的语法为 mock(class or interface)。

  1. @Before
  2. public void setUp()
  3. {
  4. this.accountDao = Mockito.mock(AccountDao.class);
  5. this.request = Mockito.mock(HttpServletRequest.class);
  6. this.accountLoginController = new AccountLoginController(accountDao);
  7. }

 

简单的理解:通过mock 模拟accountLoginController 的对象,拥有accountLoginController 的所有方法和属性  但并不是new 了一个而是伪装了一个该对象

3. 设置对象调用的预期返回值(打桩(Stubbing)  ,录制)

when(mock.someMethod()).thenReturn(value) 

设定 Mock 对象某个方法调用时返回值

  1. when(request.getParameter("username")).thenReturn("alex");
  2. when(request.getParameter("password")).thenReturn("123456");
  3. when(accountDao.findAccount(anyString(), anyString())).thenReturn(account);

stubbing的相关行为:

 

3.播放

 将录制的结果播放,同时通过断言的方式判断结果

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

 

 

四.3种不同的mock方式 

1.

@RunWith(MockitoJUnitRunner.class) 和AccountDao accountDao = mock(AccountDao.class, Mockito.RETURNS_SMART_NULLS); 方式
  1. @RunWith(MockitoJUnitRunner.class)
  2. public class MockByRunnerTest
  3. {
  4. @Test
  5. public void testMock()
  6. {
  7. AccountDao accountDao = mock(AccountDao.class, Mockito.RETURNS_SMART_NULLS);
  8. Account account = accountDao.findAccount("x", "x");
  9. System.out.println(account);
  10. }
  11. }

 

2.MockitoAnnotations.initMocks(this);和@Mock的方式来构建

  1. package com.wangwenjun.mockito.lesson03;
  2. import com.wangwenjun.mockito.common.Account;
  3. import com.wangwenjun.mockito.common.AccountDao;
  4. import org.junit.Before;
  5. import org.junit.Test;
  6. import org.mockito.Answers;
  7. import org.mockito.Mock;
  8. import org.mockito.MockitoAnnotations;
  9. public class MockByAnnotationTest
  10. {
  11. @Before
  12. public void init()
  13. {
  14. MockitoAnnotations.initMocks(this);
  15. }
  16. @Mock(answer = Answers.RETURNS_SMART_NULLS)
  17. private AccountDao accountDao;
  18. @Test
  19. public void testMock()
  20. {
  21. Account account = accountDao.findAccount("x", "x");
  22. System.out.println(account);
  23. }
  24. }

 

3. 由于@RunWith 只能加载一个,当使用junit时候 就不能加载mokcito运行器

  1. @Rule
  2. public MockitoRule mockitoRule = MockitoJUnit.rule();
  3. @Mock
  4. private AccountDao accountDao;

方式进行mock

  1. package com.wangwenjun.mockito.lesson03;
  2. import com.wangwenjun.mockito.common.Account;
  3. import com.wangwenjun.mockito.common.AccountDao;
  4. import org.junit.Rule;
  5. import org.junit.Test;
  6. import org.mockito.Answers;
  7. import org.mockito.Mock;
  8. import org.mockito.junit.MockitoJUnit;
  9. import org.mockito.junit.MockitoRule;
  10. public class MockByRuleTest
  11. {
  12. @Rule
  13. public MockitoRule mockitoRule = MockitoJUnit.rule();
  14. @Mock
  15. private AccountDao accountDao;
  16. @Test
  17. public void testMock()
  18. {
  19. // AccountDao dao = mock(AccountDao.class);
  20. Account account = accountDao.findAccount("x", "x");
  21. System.out.println(account);
  22. }
  23. }

 

了解:mock一个对象时候,能够更改默认值(待深入研究,此处只做相关提醒)

https://blog.csdn.net/dnc8371/article/details/106706971

RETURNS_DEEP_STUBS
RETURNS_MOCKS

五. Stubbing

when(mock.someMethod()).thenReturn(value) 

 

例子1:

when(mock.someMethod()).thenReturn(value) 来设定 Mock 对象某个方法调用时的返回值

when(mock.someMethod()).thenThrow(new RuntimeException) 的方式来设定当调用某个方法时抛出的异常

  1. @Test
  2. public void howToUseStubbing()
  3. {
  4. when(list.get(0)).thenReturn("first");
  5. assertThat(list.get(0), equalTo("first"));
  6. when(list.get(anyInt())).thenThrow(new RuntimeException());
  7. try
  8. {
  9. list.get(0);
  10. fail();
  11. } catch (Exception e)
  12. {
  13. assertThat(e, instanceOf(RuntimeException.class));
  14. }
  15. }

2.void类型的函数   howToStubbingVoidMethod

使用 doNothing().when(list).clear();  的方式Mock没有返回值类型的函数

使用 doThrow(RuntimeException.class).when(list).clear(); 的方式Mock没有返回值类型的函数

  1. @Test
  2. public void howToStubbingVoidMethod()
  3. {
  4. doNothing().when(list).clear();
  5. list.clear();
  6. verify(list, times(1)).clear();
  7. doThrow(RuntimeException.class).when(list).clear();
  8. try
  9. {
  10. list.clear();
  11. fail();
  12. } catch (Exception e)
  13. {
  14. assertThat(e, instanceOf(RuntimeException.class));
  15. }
  16. }

 

3.doReturn("second").when(list).get(1);

的相关写法

  1. @Test
  2. public void stubbingDoReturn()
  3. {
  4. when(list.get(0)).thenReturn("first");
  5. doReturn("second").when(list).get(1);
  6. assertThat(list.get(0), equalTo("first"));
  7. assertThat(list.get(1), equalTo("second"));
  8. }

4.  iterateSubbing  Stubbing的迭代写法、

第五次还是4

  1. @Test
  2. public void iterateSubbing()
  3. {
  4. when(list.size()).thenReturn(1).thenReturn(2).thenReturn(3).thenReturn(4);
  5. assertThat(list.size(), equalTo(1));
  6. assertThat(list.size(), equalTo(2));
  7. assertThat(list.size(), equalTo(3));
  8. assertThat(list.size(), equalTo(4));
  9. assertThat(list.size(), equalTo(4));
  10. }

运行结果

 

5.stubbingWithAnswer

 

Answer 是个泛型接口。

到调用发生时将执行这个回调,通过  Object[] args = invocation.getArguments();可以拿到调用时传入的参数,

通过 Object mock = invocation.getMock();可以拿到mock对象。

有些方法可能接口的参数为一个Listener参数,如果我们使用Answer打桩,我们就可以获取这个Listener,并且在Answer函数中执行对应的回调函数

,这对我们了解函数的内部执行过成有很大的帮助。

 

  1. @Test
  2. public void stubbingWithAnswer()
  3. {
  4. when(list.get(anyInt())).thenAnswer(invocationOnMock ->
  5. {
  6. Integer index = invocationOnMock.getArgumentAt(0, Integer.class);
  7. return String.valueOf(index * 10);
  8. });
  9. assertThat(list.get(0), equalTo("0"));
  10. assertThat(list.get(999), equalTo("9990"));
  11. }

6.stubbingWithRealCall

mock出来的对象并不会真正的去执行,而该函数将会真正执行mock对象的那个方法

  1. @Test
  2. public void stubbingWithRealCall()
  3. {
  4. StubbingService service = mock(StubbingService.class);
  5. // when(service.getS()).thenReturn("Alex");
  6. // assertThat(service.getS(), equalTo("Alex"));
  7. when(service.getI()).thenCallRealMethod();
  8. assertThat(service.getI(), equalTo(10));
  9. }

 

六.spying

           你可以为真实对象创建一个监控(spy)对象,当你使用这个spy对象时,真实的对象也会被调用,除非它的函数被打桩。你应该尽量少的使用spy对象,使用时也需要小心,例如spy对象可以用来处理遗留代码,Spy示例如下:

           mock部分的方法

  1. package com.wangwenjun.mockito.lesson06;
  2. import org.junit.Test;
  3. import org.junit.runner.RunWith;
  4. import org.mockito.runners.MockitoJUnitRunner;
  5. import java.util.ArrayList;
  6. import java.util.List;
  7. import static org.hamcrest.CoreMatchers.equalTo;
  8. import static org.junit.Assert.assertThat;
  9. import static org.mockito.Mockito.spy;
  10. import static org.mockito.Mockito.when;
  11. @RunWith(MockitoJUnitRunner.class)
  12. public class SpyingTest
  13. {
  14. @Test
  15. public void testSpy()
  16. {
  17. List<String> realList = new ArrayList<>();
  18. List<String> list = spy(realList);
  19. list.add("Mockito");
  20. list.add("PowerMock");
  21. assertThat(list.get(0), equalTo("Mockito"));
  22. assertThat(list.get(1), equalTo("PowerMock"));
  23. assertThat(list.isEmpty(), equalTo(false));
  24. when(list.isEmpty()).thenReturn(true);
  25. when(list.size()).thenReturn(0);
  26. assertThat(list.get(0), equalTo("Mockito"));
  27. assertThat(list.get(1), equalTo("PowerMock"));
  28. assertThat(list.isEmpty(), equalTo(true));
  29. assertThat(list.size(), equalTo(0));
  30. }
  31. }

 

@Spy 注解的方式实现spy
  1. package com.wangwenjun.mockito.lesson06;
  2. import org.junit.Before;
  3. import org.junit.Test;
  4. import org.mockito.MockitoAnnotations;
  5. import org.mockito.Spy;
  6. import java.util.ArrayList;
  7. import java.util.List;
  8. import static org.hamcrest.CoreMatchers.equalTo;
  9. import static org.junit.Assert.assertThat;
  10. import static org.mockito.Mockito.when;
  11. public class SpyingAnnotationTest
  12. {
  13. @Spy
  14. private List<String> list = new ArrayList<>();
  15. @Before
  16. public void init()
  17. {
  18. MockitoAnnotations.initMocks(this);
  19. }
  20. @Test
  21. public void testSpy()
  22. {
  23. list.add("Mockito");
  24. list.add("PowerMock");
  25. assertThat(list.get(0), equalTo("Mockito"));
  26. assertThat(list.get(1), equalTo("PowerMock"));
  27. assertThat(list.isEmpty(), equalTo(false));
  28. when(list.isEmpty()).thenReturn(true);
  29. when(list.size()).thenReturn(0);
  30. assertThat(list.get(0), equalTo("Mockito"));
  31. assertThat(list.get(1), equalTo("PowerMock"));
  32. assertThat(list.isEmpty(), equalTo(true));
  33. assertThat(list.size(), equalTo(0));
  34. }
  35. }

 

七.Mockito Argument Matchers

       

         any() 任意入参,经过语法检查的都会生效

         isA()  必须是该实例 该录制将会生效

         

       

  1. package com.wangwenjun.mockito.lesson07;
  2. import org.junit.Test;
  3. import org.mockito.Mockito;
  4. import java.util.ArrayList;
  5. import java.util.List;
  6. import static org.hamcrest.CoreMatchers.equalTo;
  7. import static org.hamcrest.CoreMatchers.nullValue;
  8. import static org.junit.Assert.assertThat;
  9. import static org.mockito.Mockito.*;
  10. public class ArgumentsMatcherTest
  11. {
  12. @Test
  13. public void basicTest()
  14. {
  15. List<Integer> list = mock(ArrayList.class);
  16. when(list.get(eq(0))).thenReturn(100);
  17. assertThat(list.get(0), equalTo(100));
  18. assertThat(list.get(1), nullValue());
  19. }
  20. /*isA, any*/
  21. @Test
  22. public void testComplex()
  23. {
  24. Foo foo = mock(Foo.class);
  25. when(foo.function(Mockito.isA(Child1.class))).thenReturn(100);
  26. int result = foo.function(new Child1());
  27. assertThat(result, equalTo(100));
  28. result = foo.function(new Child2());
  29. assertThat(result, equalTo(0));
  30. reset(foo);
  31. when(foo.function(Mockito.any(Child1.class))).thenReturn(100);
  32. result = foo.function(new Child2());
  33. assertThat(result, equalTo(100));
  34. }
  35. static class Foo
  36. {
  37. int function(Parent p)
  38. {
  39. return p.work();
  40. }
  41. }
  42. interface Parent
  43. {
  44. int work();
  45. }
  46. class Child1 implements Parent
  47. {
  48. @Override
  49. public int work()
  50. {
  51. throw new RuntimeException();
  52. }
  53. }
  54. class Child2 implements Parent
  55. {
  56. @Override
  57. public int work()
  58. {
  59. throw new RuntimeException();
  60. }
  61. }
  62. }

八.WORKING WITH WILDCARD MATCHERS

anyXXX()

any()

isA() 

例子:

  1. package com.wangwenjun.mockito.lesson08;
  2. import org.junit.After;
  3. import org.junit.Test;
  4. import org.junit.runner.RunWith;
  5. import org.mockito.Mock;
  6. import org.mockito.runners.MockitoJUnitRunner;
  7. import java.io.Serializable;
  8. import java.util.Collections;
  9. import java.util.List;
  10. import static org.hamcrest.CoreMatchers.equalTo;
  11. import static org.junit.Assert.assertThat;
  12. import static org.mockito.Matchers.anyCollection;
  13. import static org.mockito.Mockito.*;
  14. @RunWith(MockitoJUnitRunner.class)
  15. public class WildcardArgumentMatcherTest
  16. {
  17. @Mock
  18. private SimpleService simpleService;
  19. @Test
  20. public void wildcardMethod1()
  21. {
  22. when(simpleService.method1(anyInt(), anyString(), anyCollection(), isA(Serializable.class))).thenReturn(100);
  23. int result = simpleService.method1(1, "Alex", Collections.emptyList(), "Mockito");
  24. assertThat(result, equalTo(100));
  25. result = simpleService.method1(1, "Wang", Collections.emptySet(), "MockitoForJava");
  26. assertThat(result, equalTo(100));
  27. }
  28. @Test
  29. public void wildcardMethod1WithSpec()
  30. {
  31. when(simpleService.method1(anyInt(), anyString(), anyCollection(), isA(Serializable.class))).thenReturn(-1);
  32. when(simpleService.method1(anyInt(), eq("Alex"), anyCollection(), isA(Serializable.class))).thenReturn(100);
  33. when(simpleService.method1(anyInt(), eq("Wang"), anyCollection(), isA(Serializable.class))).thenReturn(200);
  34. int result = simpleService.method1(1, "Alex", Collections.emptyList(), "Mockito");
  35. assertThat(result, equalTo(100));
  36. result = simpleService.method1(1, "Wang", Collections.emptyList(), "Mockito");
  37. assertThat(result, equalTo(200));
  38. result = simpleService.method1(1, "sfsfs", Collections.emptyList(), "Mockito");
  39. assertThat(result, equalTo(-1));
  40. }
  41. @Test
  42. public void wildcardMethod2()
  43. {
  44. List<Object> emptyList = Collections.emptyList();
  45. doNothing().when(simpleService).method2(anyInt(), anyString(), anyCollection(), isA(Serializable.class));
  46. simpleService.method2(1, "Alex", emptyList, "Mockito");
  47. verify(simpleService, times(1)).method2(1, "Alex", emptyList, "Mockito");
  48. verify(simpleService, times(1)).method2(anyInt(), eq("Alex"), anyCollection(), isA(Serializable.class));
  49. }
  50. @After
  51. public void destroy()
  52. {
  53. reset(simpleService);
  54. }
  55. }

九.verify函数

默认验证的是执行了times(1),也就是某个测试函数是否执行了1次.因此,times(1)通常被省略了。

  1. @Test
  2. public void tesVerify()
  3. {
  4. List mockedList = mock(List.class);
  5. mockedList.add("once");
  6. mockedList.add("twice");
  7. mockedList.add("twice");
  8. mockedList.add("three times");
  9. mockedList.add("three times");
  10. mockedList.add("three times");
  11. //following two verifications work exactly the same - times(1) is used by default
  12. // 下面的两个验证函数效果一样,因为verify默认验证的就是times(1)
  13. verify(mockedList).add("once");
  14. verify(mockedList, times(1)).add("once");
  15. //exact number of invocations verification
  16. // 验证具体的执行次数
  17. verify(mockedList, times(2)).add("twice");
  18. verify(mockedList, times(3)).add("three times");
  19. //verification using never(). never() is an alias to times(0)
  20. // 使用never()进行验证,never相当于times(0)
  21. verify(mockedList, never()).add("never happened");
  22. //verification using atLeast()/atMost()
  23. // 使用atLeast()/atMost()
  24. verify(mockedList, atLeastOnce()).add("three times");
  25. // verify(mockedList, atLeast(2)).add("five times");
  26. verify(mockedList, atMost(5)).add("three times");
  27. }

 

 

 

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/繁依Fanyi0/article/detail/502636
推荐阅读
相关标签
  

闽ICP备14008679号