暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

Mockito常规使用

open资料酷 2019-09-10
699
    官网地址
    https://github.com/mockito/mockito/wiki/What%27s-new-in-Mockito-2
    wiki地址
    https://github.com/mockito/m
      Junit常用注解     作用
      @Test 测试方法
      @Ignore 忽略测试方法
      @BeforeClass 所有测试方法前执行一次 ,修饰的方法必须为static
      @AfterClass 所有测试方法后执行一次 ,修饰的方法必须为static
      @Before 初始化方法,每个方法前都执行一次
      @After           释放资源,每个方法后都执行一次
      @RunWith 指定一个特殊的运行器
      @SuteClasses 将需要进行测试的类列表作为参数传入


      1.Junit 4 的单元测试用例执行顺序为:
      @BeforeClass –> @Before –> @Test –> @After –> @AfterClass;


      2.每一个测试方法的调用顺序为:
      @Before –> @Test –> @After


      3.@Test两个参数
      (1) expected用于测试会抛出的异常,注意expected不起到catch作用,抛出异常后的代码不会被执行;
      (2) timeout,传入指定的毫秒数,用于超时测试。
        ***********************************************************注解创建*****************************************
        一:
        /**引入mock的对象*/
        @MockBean
        private EclpService eclpService;

        二:
        @Before
        public void init(){

        //当调用eclpService中的某个方法时返回某些值
        when(mock.someMethod()).thenReturn(value)

        //验证eclpService中的某个方法是否被调用
        verify(mock).someMethod()

        }
        ****************************************************************************************************
        ---------------------------------------------------创建mock对象的方式----------------------------
        (1)普通方法
        普通方法中,被测试类可以写接口,因为可以手动new出实现类
        public class UserServiceTest {
        private UserService userService;
        private UserDao mockUserDao;
        @Before
        public void setUp() {
        mockUserDao = mock(UserDao.class);
        userService = new UserServiceImpl();
        userService.setUserDao(mockUserDao);
        }
        (2)通过注解
        @InjectMocks注解标注的属性,可以自动注入标记@Mock@Spy等注解的属性值
        @InjectMocks标注的属性不能使用接口,因为@InjectMocks不能传入参数指明实现类
        public class UserServiceTest {

        @InjectMocks
        private UserServiceImpl userService;

        @Mock
        private UserDao mockUserDao;

        @Before
        public void setUp() {
        MockitoAnnotations.initMocks(this);
        }


        (3)注解创建
        参考上文***注解创建****


        ---------------------------------------------------mockito的使用-------------------------------
        when(mock.someMethod()).thenReturn(value1).thenReturn(value2);
        when(mock.someMethod()).thenReturn(value1, value2);
        when(mock.someMethod()).thenReturn(value1);
        when(mock.someMethod()).thenReturn(value2);


        另一种风格doReturn,主要用于spy对象的情况下
        doReturn(value1).doReturn(value2).when(mock).someMethod();


        void 方法进行方法预期设定
        doNothing().when(mock).someMethod();


        对方法设定返回异常
        when(mock.someMethod()).thenThrow(new RuntimeException());
        void 方法进行方法预期设定
        doThrow(new RuntimeException()).when(mock).someMethod();

        参数匹配器
        比如 any(User.class),匹配任意User对象;anyString()匹配任意字符串;anyInt()匹配任意int型


        Mock对象的行为验证
        (1)验证方法的调用次数
        通过 verify(mock,times(?)).someMethod()验证方法的调用次数,是常用的验证方式,包括可以验证指定明确的方法被调用次数、
        某方法未被调用。或一个方法总体被调用次数。
        Mockito除了提供times(N)方法供我们调用外,还提供了很多可选的方法:
        never() 没有被调用,相当于times(0)
        atLeast(N) 至少被调用N次
        atLeastOnce() 相当于atLeast(1)
        atMost(N) 最多被调用N次

        (2) 超时验证
        通过timeout,并制定毫秒数验证超时。注意,如果被调用多次,times还是需要的。


        (3) 方法调用顺序
        通过InOrder对象,验证方法的执行顺序,如上例子中,如果mock的get(0)和get(1)方法反过来则测试不通过。这里mock2其实没有被调用过。所以不需要些。


        (4) verifyNoMoreInteractions
        查询是否存在被调用,但未被验证的方法,如果存在则抛出异常。这里因为验证了get(anyInt()),相当于所有的get方法被验证,所以通过。


        (5) verifyZeroInteractions
        查询对象是否未产生交互,如果传入的mock对象的方法被调用过,则抛出异常。这里mock2的方法没有被调用过,所有通过。

        (6) 利用ArgumentCaptor(参数捕获器)捕获方法
        参数进行验证通过 ArgumentCaptor 对象的forClass(Class<T> clazz)方法来构建ArgumentCaptor对象。然后便可在验证时对方法的参数进行捕获,
        最后验证捕获的参数值。如果方法有多个参数都要捕获验证,那就需要创建多个ArgumentCaptor对象处理。
        当某个对象进行了多次调用后,比如mock对象。这时调用argument.getValue()获取到的是最后一次调用的参数。
        如果要获取所有的参数值可以调用argument.getAllValues(),它将返回参数值的List。

        Spy-对象的监视
        Mock 对象只能调用stubbed 方法,调用不了它真实的方法。但Mockito 可以监视一个真实的对象,这时对它进行方法调用时它将调用真实的方法,
        同时也可以stubbing 这个对象的方法让它返回我们的期望值。另外不论是否是真实的方法调用都可以进行verify验证。和创建mock对象一样,对于final类、
        匿名类和Java的基本类型是无法进行spy的。


        监视对象
        监视一个对象需要调用spy(T object)方法,如下面的代码中spy变量就在监视LinkedList实例。
        List spy = spy(new LinkedList());
        下面是一个官方给出的例子,仅供参考
        @Test
        public void spyTest() {
        List list = new LinkedList();
        List spy = spy(list);
        // optionally, you can stub out some methods:
        when(spy.size()).thenReturn(100);
        // using the spy calls real methods
        spy.add("one");
        spy.add("two");
        // prints "one" - the first element of a list
        System.out.println(spy.get(0));
        // size() method was stubbed - 100 is printed
        System.out.println(spy.size());
        // optionally, you can verify
        verify(spy).add("one");
        verify(spy).add("two");
        }


        Demo:
        @Test
        public void save() {
        User user = new User();
        user.setLoginName("admin");
        // 第一次调用findUserByLoginName返回user 第二次调用返回null
        when(mockUserDao.findUserByLoginName(anyString())).thenReturn(user).thenReturn(null);
        try {
        // 测试如果重名会抛出异常
        userService.save(user);
        // 如果没有抛出异常测试不通过
        failBecauseExceptionWasNotThrown(RuntimeException.class);
        } catch (ServiceException se) {
        }
        verify(mockUserDao).findUserByLoginName("admin");

        // userService.save(user);
        user.setPassword("123456");
        String userId = userService.save(user);
        // 断言返回结果
        assertThat(userId).isNotEmpty().hasSize(32);

        verify(mockUserDao, times(2)).findUserByLoginName(anyString());
        verify(mockUserDao).save(any(User.class));
        }

        @Test
        public void save2() {
        User user = new User();
        user.setLoginName("admin");
        user.setPassword("123456");
        userService.save(user);

        // 通过ArgumentCaptor(参数捕获器) 对传入参数进行验证
        ArgumentCaptor<User> argument = ArgumentCaptor.forClass(User.class);
        verify(mockUserDao).save(argument.capture());
        assertThat("admin").isEqualTo(argument.getValue().getLoginName());

        // stub 调用save方法时抛出异常
        doThrow(new ServiceException("测试抛出异常")).when(mockUserDao).save(any(User.class));
        try {
        userService.save(user);
        failBecauseExceptionWasNotThrown(RuntimeException.class);
        } catch (ServiceException se) {
        }
        }


        --------------------------------------------------断言:Assertions-------------------------------
        用来判断某个语句的结果是否为真或判断是否与预期相符
        由于JUnit的Assert是公认的烂API,所以不推荐使用,目前推荐使用的是AssertJ。


        -------------------------------------------------对字符串断言-------------------------------------
        @Test
        public void testString() {
        String str = null;
        // 断言null或为空字符串
        assertThat(str).isNullOrEmpty();
        // 断言空字符串
        assertThat("").isEmpty();
        // 断言字符串相等 断言忽略大小写判断字符串相等
        assertThat("Frodo").isEqualTo("Frodo").isEqualToIgnoringCase("frodo");
        // 断言开始字符串 结束字符穿 字符串长度
        assertThat("Frodo").startsWith("Fro").endsWith("do").hasSize(5);
        // 断言包含字符串 不包含字符串
        assertThat("Frodo").contains("rod").doesNotContain("fro");
        // 断言字符串只出现过一次
        assertThat("Frodo").containsOnlyOnce("do");
        // 判断正则匹配
        assertThat("Frodo").matches("..o.o").doesNotMatch(".*d");
        }

        --------------------------------------------------对数字断言------------------------------------------
        @Test
        public void testNumber() {
        Integer num = null;
        // 断言空
        assertThat(num).isNull();
        // 断言相等
        assertThat(42).isEqualTo(42);
        // 断言大于 大于等于
        assertThat(42).isGreaterThan(38).isGreaterThanOrEqualTo(38);
        // 断言小于 小于等于
        assertThat(42).isLessThan(58).isLessThanOrEqualTo(58);
        // 断言0
        assertThat(0).isZero();
        // 断言正数 非负数
        assertThat(1).isPositive().isNotNegative();
        // 断言负数 非正数
        assertThat(-1).isNegative().isNotPositive();
        }


        -----------------------------------------对日期断言-----------------------------------------
        @Test
        public void testDate() {
        // 断言与指定日期相同 不相同 在指定日期之后 在指定日期之钱
        assertThat(Dates.parse("2014-02-01")).isEqualTo("2014-02-01").isNotEqualTo("2014-01-01")
        .isAfter("2014-01-01").isBefore(parse("2014-03-01"));
        // 断言 2014 在指定年份之前 在指定年份之后
        assertThat(DateTime.now().toDate()).isBeforeYear(2020).isAfterYear(2013);
        // 断言时间再指定范围内 不在指定范围内
        assertThat(parse("2014-02-01")).isBetween("2014-01-01", "2014-03-01").isNotBetween(
        parse("2014-02-02"), parse("2014-02-28"));

        // 断言两时间相差100毫秒
        Date d1 = new Date();
        Date d2 = new Date(d1.getTime() + 100);
        assertThat(d1).isCloseTo(d2, 100);

        // sets dates differing more and more from date1
        Date date1 = Dates.parseDatetimeWithMs("2003-01-01T01:00:00.000");
        Date date2 = parseDatetimeWithMs("2003-01-01T01:00:00.555");
        Date date3 = parseDatetimeWithMs("2003-01-01T01:00:55.555");
        Date date4 = parseDatetimeWithMs("2003-01-01T01:55:55.555");
        Date date5 = parseDatetimeWithMs("2003-01-01T05:55:55.555");

        // 断言 日期忽略毫秒,与给定的日期相等
        assertThat(date1).isEqualToIgnoringMillis(date2);
        // 断言 日期与给定的日期具有相同的年月日时分秒
        assertThat(date1).isInSameSecondAs(date2);
        // 断言 日期忽略秒,与给定的日期时间相等
        assertThat(date1).isEqualToIgnoringSeconds(date3);
        // 断言 日期与给定的日期具有相同的年月日时分
        assertThat(date1).isInSameMinuteAs(date3);
        // 断言 日期忽略分,与给定的日期时间相等
        assertThat(date1).isEqualToIgnoringMinutes(date4);
        // 断言 日期与给定的日期具有相同的年月日时
        assertThat(date1).isInSameHourAs(date4);
        // 断言 日期忽略小时,与给定的日期时间相等
        assertThat(date1).isEqualToIgnoringHours(date5);
        // 断言 日期与给定的日期具有相同的年月日
        assertThat(date1).isInSameDayAs(date5);
        }

        -------------------------------------对List断言--------------------------------------------
        @Test
        public void testList() {
        // 断言 列表是空的
        assertThat(newArrayList()).isEmpty();
        // 断言 列表的开始 结束元素
        assertThat(newArrayList(1, 2, 3)).startsWith(1).endsWith(3);
        // 断言 列表包含元素 并且是排序的
        assertThat(newArrayList(1, 2, 3)).contains(1, atIndex(0)).contains(2, atIndex(1)).contains(3)
        .isSorted();
        // 断言 被包含与给定列表
        assertThat(newArrayList(3, 1, 2)).isSubsetOf(newArrayList(1, 2, 3, 4));
        // 断言 存在唯一元素
        assertThat(Lists.newArrayList("a", "b", "c")).containsOnlyOnce("a");
        }


        ---------------------------------------对Map断言---------------------------------------------
        @Test
        public void testMap() {
        Map<String, Object> foo = Maps.newHashMap();
        foo.put("A", 1);
        foo.put("B", 2);
        foo.put("C", 3);

        // 断言 map 不为空 size
        assertThat(foo).isNotEmpty().hasSize(3);
        // 断言 map 包含元素
        assertThat(foo).contains(entry("A", 1), entry("B", 2));
        // 断言 map 包含key
        assertThat(foo).containsKeys("A", "B", "C");
        // 断言 map 包含value
        assertThat(foo).containsValue(3);
        }


        ---------------------------------------对Class断言------------------------------------
        @Test
        public void testClass() {
        // 断言 是注解
        assertThat(Magical.class).isAnnotation();
        // 断言 不是注解
        assertThat(Ring.class).isNotAnnotation();
        // 断言 存在注解
        assertThat(Ring.class).hasAnnotation(Magical.class);
        // 断言 不是借口
        assertThat(Ring.class).isNotInterface();
        // 断言 是否为指定Class实例
        assertThat("string").isInstanceOf(String.class);
        // 断言 类是给定类的父类
        assertThat(Person.class).isAssignableFrom(Employee.class);
        }

        @Magical
        public enum Ring {
        oneRing, vilya, nenya, narya, dwarfRing, manRing;
        }
        @Target(ElementType.TYPE)
        @Retention(RetentionPolicy.RUNTIME)
        public @interface Magical {}
        public class Person {}
        public class Employee extends Person {}


        -------------------------------------使用fail方法-------------------------------------------
        @Test
        public void testFail() {
        try {
        fail("在不检查任何条件的情况下使断言失败。显示一则消息");
        } catch (AssertionError ae) {
        logger.info("可以通过catch捕获该Error");
        }
        try {
        failBecauseExceptionWasNotThrown(ServiceException.class);
        } catch (AssertionError ae) {
        logger.info("可以通过catch捕获该Error");
        }
        }


        文章转载自open资料酷,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

        评论