51Testing软件测试论坛

标题: 测试杂谈及常见单元测试框架入门 [打印本页]

作者: lsekfe    时间: 2022-4-20 11:48
标题: 测试杂谈及常见单元测试框架入门
单元测试框架
  mockito
  1、单元测试框架:EasyMock,Mockito
  2、大多 Java Mock 库如 EasyMock 或 Mockito 都是 expect-run-verify (期望-运行-验证)方式,而 Mockito 则使用更简单,更直观的方法。
  3、mokito好处:
  ·无需昂贵的前期启动
  · 拥有很好的API,几乎没有时间成本
  · 可以mock接口和类
  · 步骤:执行前stub,在交互中验证
  · 支持andriod
  初体验
  1、验证交互行为
  1.  import static org.mockito.Mockito.*;
  2.   // mock creation
  3.   List mockedList = mock(List.class);
  4.   // using mock object - it does not throw any "unexpected interaction" exception
  5.   mockedList.add("one");
  6.   mockedList.clear();
  7.   // selective, explicit, highly readable verification
  8.   verify(mockedList).add("one");
  9.   verify(mockedList).clear();
复制代码
一旦创建mock,就会记住所有的交互,可以自行选择需要的。
  2、方法返回
  1.  // you can mock concrete classes, not only interfaces
  2.   LinkedList mockedList = mock(LinkedList.class);
  3.   // stubbing appears before the actual execution
  4.   when(mockedList.get(0)).thenReturn("first");
  5.   // the following prints "first"
  6.   System.out.println(mockedList.get(0));
  7.   // the following prints "null" because get(999) was not stubbed
  8.   System.out.println(mockedList.get(999));
复制代码
 mock方法返回。

  3、参数匹配
  1. //stubbing using built-in anyInt() argument matcher
  2.    when(mockedList.get(anyInt())).thenReturn("element");
  3.    //stubbing using custom matcher (let's say isValid() returns your own matcher implementation):
  4.    when(mockedList.contains(argThat(isValid()))).thenReturn(true);
  5.    //following prints "element"
  6.    System.out.println(mockedList.get(999));
  7.    //you can also verify using an argument matcher
  8.    verify(mockedList).get(anyInt());
  9.    //argument matchers can also be written as Java 8 Lambdas
  10.    verify(mockedList).add(argThat(someString -> someString.length() > 5));
复制代码
注意:参数如果过使用匹配器,所有参数必须使用匹配器提供。
  1. verify(mock).someMethod(anyInt(), anyString(), eq("third argument"));
  2.      //above is correct - eq() is also an argument matcher
  3.      verify(mock).someMethod(anyInt(), anyString(), "third argument");
  4.      //above is incorrect - exception will be thrown because third argument is given without an argument matcher.
复制代码
4、验证确切的调用次数
  1. //using mock
  2.    mockedList.add("once");
  3.    mockedList.add("twice");
  4.    mockedList.add("twice");
  5.    mockedList.add("three times");
  6.    mockedList.add("three times");
  7.    mockedList.add("three times");
  8.    //following two verifications work exactly the same - times(1) is used by default
  9.    verify(mockedList).add("once");
  10.    verify(mockedList, times(1)).add("once");
  11.    //exact number of invocations verification
  12.    verify(mockedList, times(2)).add("twice");
  13.    verify(mockedList, times(3)).add("three times");
  14.    //verification using never(). never() is an alias to times(0)
  15.    verify(mockedList, never()).add("never happened");
  16.    //verification using atLeast()/atMost()
  17.    verify(mockedList, atMostOnce()).add("once");
  18.    verify(mockedList, atLeastOnce()).add("three times");
  19.    verify(mockedList, atLeast(2)).add("three times");
  20.    verify(mockedList, atMost(5)).add("three times");
复制代码
默认是times(1), 所以可以显示省略times(1)
5、异常处理
  1. doThrow(new RuntimeException()).when(mockedList).clear();
  2.      //following throws RuntimeException:
  3.      mockedList.clear();
复制代码
6、验证顺序
  1. // A. Single mock whose methods must be invoked in a particular order
  2.    List singleMock = mock(List.class);
  3.    //using a single mock
  4.    singleMock.add("was added first");
  5.    singleMock.add("was added second");
  6.    //create an inOrder verifier for a single mock
  7.    InOrder inOrder = inOrder(singleMock);
  8.    //following will make sure that add is first called with "was added first", then with "was added second"
  9.    inOrder.verify(singleMock).add("was added first");
  10.    inOrder.verify(singleMock).add("was added second");
  11.    // B. Multiple mocks that must be used in a particular order
  12.    List firstMock = mock(List.class);
  13.    List secondMock = mock(List.class);
  14.    //using mocks
  15.    firstMock.add("was called first");
  16.    secondMock.add("was called second");
  17.    //create inOrder object passing any mocks that need to be verified in order
  18.    InOrder inOrder = inOrder(firstMock, secondMock);
  19.    //following will make sure that firstMock was called before secondMock
  20.    inOrder.verify(firstMock).add("was called first");
  21.    inOrder.verify(secondMock).add("was called second");
  22.    // Oh, and A + B can be mixed together at will
复制代码
创建InOrder对象实现,支持多个mock对象的顺序。

  7、验证从未发生过调用/冗余调用
  1. //using mocks - only mockOne is interacted
  2.    mockOne.add("one");
  3.    //ordinary verification
  4.    verify(mockOne).add("one");
  5.    //verify that method was never called on a mock
  6.    verify(mockOne, never()).add("two");
  7.    //verify that other mocks were not interacted
  8.    verifyZeroInteractions(mockTwo, mockThree);
复制代码
  1. //using mocks
  2.    mockedList.add("one");
  3.    mockedList.add("two");
  4.    verify(mockedList).add("one");
  5.    //following verification will fail
  6.    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);
  1. //目标service  
  2.      @InjectMocks
  3.       private CommonService commonService;
  4.      //mock的service
  5.       @Mock
  6.       private CustomerService customerService;
  7.       @Test
  8.       public void checkLoginNameAndGetCustomer() {
  9.          //mock方法设置返回值
  10.           Mockito.when(this.customerService.findByLoginName("cnn"))
  11.               .thenAnswer((InvocationOnMock mock) -> new CustCustomer());
  12.           //测试目标方便并验证
  13.           Assert.notNull(this.commonService.checkLoginNameAndGetCustomer("cnn"), "为空");
  14.           //验证mock的方法是否有调用
  15.           Mockito.verify(this.customerService).findByLoginName("cnn");
  16.       }
复制代码
- 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软件测试论坛 (http://bbs.51testing.com/) Powered by Discuz! X3.2