51Testing软件测试论坛

 找回密码
 (注-册)加入51Testing

QQ登录

只需一步,快速开始

微信登录,快人一步

手机号码,快捷登录

查看: 1140|回复: 0
打印 上一主题 下一主题

[转贴] 测试杂谈及常见单元测试框架入门

[复制链接]
  • TA的每日心情
    无聊
    4 天前
  • 签到天数: 1050 天

    连续签到: 1 天

    [LV.10]测试总司令

    跳转到指定楼层
    1#
    发表于 2022-4-20 11:48:58 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
    单元测试框架
      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自带。






    分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
    收藏收藏
    回复

    使用道具 举报

    本版积分规则

    关闭

    站长推荐上一条 /1 下一条

    小黑屋|手机版|Archiver|51Testing软件测试网 ( 沪ICP备05003035号 关于我们

    GMT+8, 2024-11-25 18:07 , Processed in 0.059599 second(s), 24 queries .

    Powered by Discuz! X3.2

    © 2001-2024 Comsenz Inc.

    快速回复 返回顶部 返回列表