测试杂谈及常见单元测试框架入门

发表于:2022-4-20 09:52

字体: | 上一篇 | 下一篇 | 我要投稿

 作者:白萝卜弟弟    来源:稀土掘金

  单元测试框架
  mockito
  1、单元测试框架:EasyMock,Mockito
  2、大多 Java Mock 库如 EasyMock 或 Mockito 都是 expect-run-verify (期望-运行-验证)方式,而 Mockito 则使用更简单,更直观的方法。
  3、mokito好处:
  ·无需昂贵的前期启动
  · 拥有很好的API,几乎没有时间成本
  · 可以mock接口和类
  · 步骤:执行前stub,在交互中验证
  · 支持andriod
  初体验
  1、验证交互行为
  import static org.mockito.Mockito.*;
  // mock creation
  List mockedList = mock(List.class);
  // using mock object - it does not throw any "unexpected interaction" exception
  mockedList.add("one");
  mockedList.clear();
  // selective, explicit, highly readable verification
  verify(mockedList).add("one");
  verify(mockedList).clear();

  一旦创建mock,就会记住所有的交互,可以自行选择需要的。
  2、方法返回
  // you can mock concrete classes, not only interfaces
  LinkedList mockedList = mock(LinkedList.class);
  // stubbing appears before the actual execution
  when(mockedList.get(0)).thenReturn("first");
  // the following prints "first"
  System.out.println(mockedList.get(0));
  // the following prints "null" because get(999) was not stubbed
  System.out.println(mockedList.get(999));
  mock方法返回。

  3、参数匹配
   //stubbing using built-in anyInt() argument matcher
   when(mockedList.get(anyInt())).thenReturn("element");
   //stubbing using custom matcher (let's say isValid() returns your own matcher implementation):
   when(mockedList.contains(argThat(isValid()))).thenReturn(true);
   //following prints "element"
   System.out.println(mockedList.get(999));
   //you can also verify using an argument matcher
   verify(mockedList).get(anyInt());
   //argument matchers can also be written as Java 8 Lambdas
   verify(mockedList).add(argThat(someString -> someString.length() > 5));

  注意:参数如果过使用匹配器,所有参数必须使用匹配器提供。
     verify(mock).someMethod(anyInt(), anyString(), eq("third argument"));
     //above is correct - eq() is also an argument matcher
     verify(mock).someMethod(anyInt(), anyString(), "third argument");
     //above is incorrect - exception will be thrown because third argument is given without an argument matcher.

  4、验证确切的调用次数
  //using mock
   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(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)
   verify(mockedList, never()).add("never happened");
   //verification using atLeast()/atMost()
   verify(mockedList, atMostOnce()).add("once");
   verify(mockedList, atLeastOnce()).add("three times");
   verify(mockedList, atLeast(2)).add("three times");
   verify(mockedList, atMost(5)).add("three times");

  默认是times(1), 所以可以显示省略times(1)

  5、异常处理
     doThrow(new RuntimeException()).when(mockedList).clear();
     //following throws RuntimeException:
     mockedList.clear();

  6、验证顺序
   // A. Single mock whose methods must be invoked in a particular order
   List singleMock = mock(List.class);
   //using a single mock
   singleMock.add("was added first");
   singleMock.add("was added second");
   //create an inOrder verifier for a single mock
   InOrder inOrder = inOrder(singleMock);
   //following will make sure that add is first called with "was added first", then with "was added second"
   inOrder.verify(singleMock).add("was added first");
   inOrder.verify(singleMock).add("was added second");
   // B. Multiple mocks that must be used in a particular order
   List firstMock = mock(List.class);
   List secondMock = mock(List.class);
   //using mocks
   firstMock.add("was called first");
   secondMock.add("was called second");
   //create inOrder object passing any mocks that need to be verified in order
   InOrder inOrder = inOrder(firstMock, secondMock);
   //following will make sure that firstMock was called before secondMock
   inOrder.verify(firstMock).add("was called first");
   inOrder.verify(secondMock).add("was called second");
   // Oh, and A + B can be mixed together at will

  创建InOrder对象实现,支持多个mock对象的顺序。

  7、验证从未发生过调用/冗余调用
  //using mocks - only mockOne is interacted
   mockOne.add("one");
   //ordinary verification
   verify(mockOne).add("one");
   //verify that method was never called on a mock
   verify(mockOne, never()).add("two");
   //verify that other mocks were not interacted
   verifyZeroInteractions(mockTwo, mockThree);

  //using mocks
   mockedList.add("one");
   mockedList.add("two");
   verify(mockedList).add("one");
   //following verification will fail
   verifyNoMoreInteractions(mockedList);

  基本使用方法
  1、基本的API
  ·mock()/@Mock:创建mock对象
  · spy()/@Spy: 部分mock,真实的方法会被调用,依然可以被验证和stub
  · @InjectMocks:自动注入mock/spy字段(@Spy或者@Mock修饰的字段)
  · verify():验证指定的方法是否调用
  2、mock方式:
  · 注解3种方式
    - @RunWith(MockitoJUnitRunner.class) 基于junit4或者
    - before方法里添加 MockitoAnnotations.openMocks(this);
     //目标service  
     @InjectMocks
      private CommonService commonService;
     //mock的service
      @Mock
      private CustomerService customerService;
      @Test
      public void checkLoginNameAndGetCustomer() {
         //mock方法设置返回值
          Mockito.when(this.customerService.findByLoginName("cnn"))
              .thenAnswer((InvocationOnMock mock) -> new CustCustomer());
          //测试目标方便并验证
          Assert.notNull(this.commonService.checkLoginNameAndGetCustomer("cnn"), "为空");
          //验证mock的方法是否有调用
          Mockito.verify(this.customerService).findByLoginName("cnn");
      }

    - MockitoJUnit.rule()

  · 非注解(略)

  easyMock
  初体验
  @RunWith(EasyMockRunner.class)
  public class ExampleTest {
  //目标类
    @TestSubject
    private ClassUnderTest classUnderTest = new ClassUnderTest(); // 2
    @Mock
    private Collaborator mock; // 1
    @Test
    public void testRemoveNonExistingDocument() {
       // ... 期望操作
      replay(mock);
      classUnderTest.removeDocument("Does not exist");
        // ... 验证
        verify()
    }
  }

  基本使用方法
  常见注解
  @Mock,@TestSubject等
  
  总结:
  1、有效提高代码质量,不适合单元测试的代码不是好代码。
  2、提升自测效率,不需要启动spring容器。
  3、快速排除隐藏bug,弥补功能测试不到位的地方。
  4、推荐使用mockito,因为springboot自带。

  本文内容不用于商业目的,如涉及知识产权问题,请权利人联系51Testing小编(021-64471599-8017),我们将立即处理
《2023软件测试行业现状调查报告》独家发布~

关注51Testing

联系我们

快捷面板 站点地图 联系我们 广告服务 关于我们 站长统计 发展历程

法律顾问:上海兰迪律师事务所 项棋律师
版权所有 上海博为峰软件技术股份有限公司 Copyright©51testing.com 2003-2024
投诉及意见反馈:webmaster@51testing.com; 业务联系:service@51testing.com 021-64471599-8017

沪ICP备05003035号

沪公网安备 31010102002173号