首页 > 其他分享 >单元测试(二)

单元测试(二)

时间:2023-07-09 14:23:08浏览次数:40  
标签:mockito 单元测试 example User import org public

本节主要介绍Mockito ,接上篇:https://www.cnblogs.com/javaXRG/p/17537364.html

1、基础用法

1.1 工程代码

 1 package org.example.Domain;
 2 
 3 import lombok.AllArgsConstructor;
 4 import lombok.Data;
 5 
 6 @Data
 7 @AllArgsConstructor
 8 public class User {
 9 
10     private Long id;
11 
12     private String userName;
13 
14     private String password;
15 }
 1 package org.example.dao;
 2 
 3 import org.example.Domain.User;
 4 import org.springframework.stereotype.Service;
 5 
 6 import java.util.HashMap;
 7 import java.util.Map;
 8 
 9 // dao层
10 @Service
11 public class UserDao {
12 
13     public static Map<Long, User> cache = new HashMap<>();
14 
15     public User findUser(String userName, String password) {
16         // 执行查询操作
17         return null;
18     }
19 
20     public void insert(User user) {
21         // 执行入库操作
22     }
23 
24     public User findByCache(long id) {
25         return cache.get(id);
26     }
27 
28     public void putIntoCache(User user) {
29         cache.put(user.getId(), user);
30     }
31 }
package org.example.service;

import org.example.Domain.User;
import org.example.dao.UserDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
// service层
@Service
public class UserService {

    @Autowired
    private UserDao userDao;

    public User findUser(String userName, String password) {
        return userDao.findUser(userName, password);
    }

    public void insert(User user) {
        userDao.insert(user);
    }

    public User findByCache(long id) {
        return userDao.findByCache(id);
    }
}
 1 package org.example.controller;
 2 
 3 import org.example.Domain.User;
 4 import org.example.service.UserService;
 5 import org.springframework.beans.factory.annotation.Autowired;
 6 import org.springframework.stereotype.Controller;
 7 
 8 @Controller
 9 public class UserController {
10 
11     @Autowired
12     private UserService userService;
13 
14     public User findUser(String userName, String password) {
15         return userService.findUser(userName, password);
16     }
17 
18     public void insert(User user) {
19         userService.insert(user);
20     }
21 }

1.2 单测

对service中的方法进行单测

 1 package org.example.service;
 2 
 3 import org.example.Domain.User;
 4 import org.example.dao.UserDao;
 5 import org.junit.Test;
 6 import org.junit.runner.RunWith;
 7 import org.mockito.ArgumentMatchers;
 8 import org.mockito.InjectMocks;
 9 import org.mockito.Mock;
10 import org.mockito.junit.MockitoJUnitRunner;
11 
12 import static org.junit.Assert.*;
13 import static org.mockito.ArgumentMatchers.any;
14 import static org.mockito.Mockito.*;
15 
16 @RunWith(MockitoJUnitRunner.class)
17 public class UserServiceTest {
18 
19     @InjectMocks
20     private UserService userService;
21 
22     // mock userDao(基于cgLib实现一个proxy对象)
23     @Mock
24     private UserDao userDao;
25 
26     @Test
27     public void findUserTest() {
28         // 打桩 stubbing
29         when(userDao.findUser("zhangsan", "123456")).thenReturn(new User(1L, "zhangsan", "123456"));
30         // 执行方法
31         User user = userService.findUser("zhangsan", "123456");
32         // 断言
33         assertNotNull(user);
34         assertEquals(1L, user.getId().longValue());
35         assertEquals("zhangsan", user.getUserName());
36         assertEquals("123456", user.getPassword());
37     }
38 
39     @Test
40     public void insertUserTest() {
41         // void方法采用doNothing().when().xxxMethod()语法
42         doNothing().when(userDao).insert(any(User.class));
43         User user = new User(1L, "zhangsan", "123456");
44         userService.insert(user);
45         verify(userDao).insert(user);
46     }
47 
48     /**
49      * thenThrow方法抛出异常
50      */
51     @Test(expected = RuntimeException.class)
52     public void throwTest() {
53         when(userDao.findUser("zhangsan", "123456")).thenThrow(new RuntimeException("用户名或密码错误"));
54         userService.findUser("zhangsan", "123456");
55     }
56 
57     /**
58      * void方法抛出异常
59      */
60     @Test(expected = RuntimeException.class)
61     public void voidMethodThrowTest() {
62         doThrow(RuntimeException.class).when(userDao).insert(any(User.class));
63         userService.insert(new User(1L, "zhangsan", "123456"));
64     }
65 }

1.3 复杂返回值构造

package org.example.service;

import org.example.Domain.User;
import org.example.dao.UserDao;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;

import static org.junit.Assert.*;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.when;

@RunWith(MockitoJUnitRunner.class)
public class UserServiceTest1 {

    @InjectMocks
    private UserService userService;

    @Mock
    private UserDao userDao;

    /**
     * 当返回值逻辑比较复杂时,可用thenAnswer进行编码式处理
     */
    @Test
    public void thenAnswerTest() {
        when(userDao.findUser(anyString(), anyString())).thenAnswer(invocationOnMock ->
                invocationOnMock.getArguments()[0].toString().startsWith("visitor") ?
                        new User(100L, "visitor-1", "234567") : null
        );
        assertNull(userService.findUser("zhangsan", "123456"));
        assertNotNull(userService.findUser("visitor-1", "234567"));
    }

    /**
     * thenReturn返回多个值
     */
    @Test
    public void thenReturnMoreTest() {
        when(userDao.findUser(anyString(), anyString())).thenReturn(
                new User(1L, "zhangsan", "123456"),
                new User(2L, "lisi", "23456"),
                new User(3L, "wangwu", "345678")
        );
        // 每次调用返回 thenReturn对应序号结果
        assertEquals(1L, userService.findUser("zhangsan", "123456").getId().intValue());
        assertEquals(2L, userService.findUser("zhangsan", "123456").getId().intValue());
        assertEquals(3L, userService.findUser("zhangsan", "123456").getId().intValue());
        // 调用次数超过最大次数时,返回最后一个值
        assertEquals(3L, userService.findUser("zhangsan", "123456").getId().intValue());
        assertEquals(3L, userService.findUser("zhangsan", "123456").getId().intValue());
    }
}

1.4 复杂参数构造

package org.example.service;

import org.assertj.core.util.Preconditions;
import org.example.Domain.User;
import org.example.dao.UserDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class UserService1 {

    @Autowired
    private UserDao userDao;

    public void insertAndSendMessage(String userName) {
        // 局部变量
        User user = new User(userName);
        userDao.insert(user);

        // 数据库自增id
        Long id = user.getId();
        Preconditions.checkNotNull(id);

        // 发送mq消息
    }

}
 1 package org.example;
 2 
 3 import org.example.Domain.User;
 4 import org.example.dao.UserDao;
 5 import org.example.service.UserService1;
 6 import org.junit.Ignore;
 7 import org.junit.Test;
 8 import org.junit.runner.RunWith;
 9 import org.mockito.ArgumentMatcher;
10 import org.mockito.ArgumentMatchers;
11 import org.mockito.InjectMocks;
12 import org.mockito.Mock;
13 import org.mockito.junit.MockitoJUnitRunner;
14 
15 import static org.mockito.ArgumentMatchers.anyString;
16 import static org.mockito.ArgumentMatchers.eq;
17 import static org.mockito.Mockito.*;
18 
19 @RunWith(MockitoJUnitRunner.class)
20 public class ArgumentMatcherTest {
21 
22     @InjectMocks
23     private UserService1 userService1;
24 
25     @Mock
26     private UserDao userDao;
27 
28     /**
29      * 该用例执行会报错,原因:
30      * 如果使用菜参数匹配,该次调用的所有参数必须是参数匹配方式
31      */
32     @Test
33     @Ignore
34     public void argumentMatcherTest1() {
35         when(userDao.findUser("zhangsan", anyString())).thenReturn(new User(1L, "zhagnsan", "123456"));
36     }
37 
38     /**
39      * 可使用eq()语法解决上述问题
40      */
41     @Test
42     public void argumentMatcherTest2() {
43         when(userDao.findUser(eq("zhangsan"), anyString())).thenReturn(new User(1L, "zhagnsan", "123456"));
44     }
45 
46     @Test
47     public void argumentMatcherTes3() {
48         when(userDao.findUser(ArgumentMatchers.argThat(new ArgumentMatcher<String>() {
49             @Override
50             public boolean matches(String s) {
51                 // 判断参数是否匹配逻辑
52                 return false;
53             }
54         }), anyString())).thenReturn(new User(1L, "zhangsan", "123456"));
55     }
56 
57     @Test
58     public void argumentMatcherTes4() {
59         when(userDao.findUser(isA(String.class), isA(String.class))).thenReturn(new User(1L, "zhangsan", "123456"));
60     }
61 
62     @Test
63     public void insertAndSendMessageTest() {
64         doNothing().when(userDao).insert(ArgumentMatchers.argThat(user -> {
65             user.setId(100L);
66             return true;
67         }));
68         userService1.insertAndSendMessage("zhangsan");
69         verify(userDao, times(1)).insert(new User(100L, "zhangsan", null));
70     }
71 }

1.5 mock对象执行真实方法

 1 package org.example.service;
 2 
 3 import org.example.Domain.User;
 4 import org.example.dao.UserDao;
 5 import org.junit.Test;
 6 import org.junit.runner.RunWith;
 7 import org.mockito.InjectMocks;
 8 import org.mockito.Mock;
 9 import org.mockito.junit.MockitoJUnitRunner;
10 
11 import static org.junit.Assert.assertEquals;
12 import static org.mockito.ArgumentMatchers.any;
13 import static org.mockito.Mockito.*;
14 
15 @RunWith(MockitoJUnitRunner.class)
16 public class UserServiceTest2 {
17 
18     @InjectMocks
19     private UserService userService;
20 
21     @Mock
22     private UserDao userDao;
23 
24     /**
25      * mock对象创建的方法,都不会真正的执行原始方法
26      * 如果想执行原始方法,可以使用:
27      * when().thenCallRealMethod()
28      * 或
29      * doCallRealMethod().when().method()
30      */
31     @Test
32     public void callRealMethodTest() {
33         doCallRealMethod().when(userDao).putIntoCache(any(User.class));
34         when(userDao.findByCache(1L)).thenCallRealMethod();
35         userDao.putIntoCache(new User(1L, "zhangsan", "123456"));
36         User user = userService.findByCache(1L);
37         assertEquals("zhangsan", user.getUserName());
38         verify(userDao, times(1)).putIntoCache(user);
39     }
40 }

1.6 @InjectMocks + spy解决多层依赖问题

package org.example.controller;

import org.example.Domain.User;
import org.example.dao.UserDao;
import org.example.service.UserService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;

import static org.junit.Assert.*;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;

@RunWith(MockitoJUnitRunner.class)
public class UserControllerTest {

    @InjectMocks
    private UserController userController;

    /**
     * @InjectMocks + spy() 解决多层依赖问题
     */
    @InjectMocks
    private UserService userService = spy(UserService.class);

    @Mock
    private UserDao userDao;


    @Test
    public void findUser() {
        when(userDao.findUser(anyString(), anyString())).thenReturn(new User(1L, "zhangsan", "123456"));
        User user = userController.findUser("zhangsan", "123456");
        assertEquals("zhangsan", user.getUserName());
    }
}

1.7 @Spy

package org.example;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.Spy;
import org.mockito.junit.MockitoJUnitRunner;

import java.util.ArrayList;

import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.doReturn;

@RunWith(MockitoJUnitRunner.class)
public class SpyTest {

    @Mock
    private ArrayList<Integer> mockList;

    /**
     * 注意:这里不能是接口,因为无法初始化并执行
     */
    @Spy
    private ArrayList<Integer> spyList;

    @Test
    public void spyCallRealMethodTest() {
        mockList.add(1);
        mockList.add(2);
        assertEquals(0, mockList.size());

        spyList.add(1);
        spyList.add(2);
        assertEquals(2, spyList.size());
    }

    /**
     * spy方法默认执行,可通过doReturn().when().method()方法让其不执行
     */
    @Test
    public void spyDoNotCallRealMethodTest() {
        doReturn(true).when(spyList).add(1);
        doReturn(true).when(spyList).add(2);
        spyList.add(1);
        spyList.add(2);
        assertEquals(0, spyList.size());
    }
}

1.8 断言

Assert、MatcherAssert、CoreMatchers断言

package org.example;

import org.example.Domain.User;
import org.hamcrest.CoreMatchers;
import org.junit.Assert;
import org.junit.Test;

import java.util.Arrays;

import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.hasItems;

import static org.hamcrest.CoreMatchers.allOf;
import static org.hamcrest.CoreMatchers.anyOf;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.everyItem;
import static org.hamcrest.CoreMatchers.not;
import static org.hamcrest.CoreMatchers.sameInstance;
import static org.hamcrest.CoreMatchers.startsWith;
import org.hamcrest.core.CombinableMatcher;
import static org.hamcrest.CoreMatchers.is;


public class MatcherAssertTest {

    @Test
    public void test1() {
        User user = new User(1L, "zhangsan", "123456");
        Boolean boolen = CoreMatchers.any(User.class).matches(user);
        Assert.assertTrue(boolen);
    }

    @Test
    public void test2() {
        User user = new User(1L, "zhangsan", "123456");
        Assert.assertThat(user, CoreMatchers.any(User.class));
    }

    // JUnit Matchers assertThat
    @Test
    public void testAssertThatBothContainsString() {
        assertThat("albumen", CoreMatchers.both(containsString("a")).and(containsString("b")));
    }

    @Test
    public void testAssertThatHasItems() {
        assertThat(Arrays.asList("one", "two", "three"), hasItems("one", "three"));
    }

    @Test
    public void testAssertThatEveryItemContainsString() {
        assertThat(Arrays.asList(new String[] { "fun", "ban", "net" }), everyItem(containsString("n")));
    }

    // Core Hamcrest Matchers with assertThat
    @Test
    public void testAssertThatHamcrestCoreMatchers() {
        assertThat("good", allOf(equalTo("good"), startsWith("good")));
        assertThat("good", not(allOf(equalTo("bad"), equalTo("good"))));
        assertThat("good", anyOf(equalTo("bad"), equalTo("good")));
        assertThat(7, not(CombinableMatcher.<Integer>either(equalTo(3)).or(equalTo(4))));
        assertThat(new Object(), not(sameInstance(new Object())));
    }

    @Test
    public void testHamcrest() throws Exception {
        assertThat(3, is(3));
        assertThat(3, is(not(4)));
    }
}

2 语法

2.1 如何创建mock对象

  • Mockito.mock(Class)方法创建
  • 通过@Mock注解创建,@RunWith(MockitoJUnitRunner.class)方式激活,@InjectMocks方式注入

2.2 如何打桩(stubbing)


需求 非void方法 void方法
语法 when(obj.method()).thenReturn(xxx); doNothing().when(obj).method();
返回值 thenReturn();  
抛异常 thenThrow() doThrow()
复杂返回逻辑 thenAnswer()  
执行原方法 thenCallRealMethod() doCallRealMethod()
断言 assertEquals(expected,actual) verify(obj,times(1)).method()

3.3 @Spy和@Mock区别


特征 @Mock @Spy
执行真实方法 thenCallRealMethod() 默认执行
不执行真实方法 默认不执行 doReturn().when()
是否能定义接口 否,因为spy方法需要执行,因此必须是个可实例化的类,不能是接口

标签:mockito,单元测试,example,User,import,org,public
From: https://www.cnblogs.com/javaXRG/p/17538157.html

相关文章

  • 单元测试 - Moq
    测试方法//准备MockIFoo接口varmock=newMock<IFoo>();//配置准备模拟的方法,当调用接口中的DoSomething方法,并传递参数"bing"的时候,返回truemock.Setup(foo=>foo.DoSomething("ping")).Returns(true);//方法的参数中使用了out参数//outargumentsvarou......
  • 软件测试常用工具总结(测试管理、单元测试、接口测试、自动化测试、性能测试、负载测试
    在软件测试的过程中,多多少少都是会接触到一些测试工具,作为辅助测试用的,以提高测试工作的效率,使用好了测试工具,能对测试起到一个很好的作用,同时,有些公司,也会要求掌握一些测试工具,或者,是在面试时,也会被问到测试工具的,比如,在面试时,最常见的问题便是,你在测试时,用的是什么测试工具?或者......
  • 单元测试-异常测试
    前面的文章(Java中的单元测试)已经说过单元测试中的mock测试,大都是正常分支下的测试,异常测试用于测试某些场景下是否会触发指定的异常,用来验证代码逻辑的正确性。目前根据Junit的版本有三种不同的方式,如下:1、@Test注解中的expected属性此方式比较简单,但是存在局限性,就是只能判断异......
  • C#中各单元测试框架比对
    下面是关于NUnit、xUnit.net、MSTest、SpecFlow和FluentAssertions等单元测试框架的优势和适用场景的简要比较:NUnit框架:优势:NUnit是一个历史悠久且成熟的框架,提供了广泛的功能和灵活性。它具有强大的断言库、丰富的扩展插件和广泛的社区支持。劣势:对初学者来说,可能存在一些学习曲线......
  • mybatis单元测试(无需启动容器)
    一、浅析相关类参考文档:https://blog.csdn.net/weixin_44778952/article/details/1096611251ConfigurationMyBatis在启动时会取读取所有配置文件,然后加载到内存中,Configuration类就是承载整个配置的类。SqlSessionFactoryBuilder调用build方法创建SqlSessionFactory,而SqlSessio......
  • 三. 软件工程 --- 单元测试
    1.单元测试(UnitTesting):是对软件中的最小可测试单元进行检查和验证。单元是构造软件系统的基础,只有使每个单元都得到足够的测试,系统的质量才能有可靠的保证,即单元测试是构筑产品质量的基石。 不能把单元测试任务堆积到系统测试阶段,否则大量故障堆积在项目中后期,项目后10%的......
  • Debug Golang源码中的单元测试
    goland配置如上,既可以debuggolang源码中的单元测试。......
  • 自媒体文章审核单元测试
    packagecom.heima.wemedia.test.service;importcom.heima.wemedia.WemediaApplication;importcom.heima.wemedia.service.WmNewsAutoScanService;importorg.junit.Test;importorg.junit.runner.RunWith;importorg.springframework.beans.factory.annotation.Autow......
  • 【转】Java 单元测试
    Java单元测试在测试方法上添加@Test注解:   ......
  • C 语言常用单元测试框架
    C语言常用单元测试框架1.C单元测试框架1.1什么是单元测试和单元测试框架单元测试是软件测试重要步骤,是对软件中最小可测试单元,在与其他部分隔离情况下,进行检查校验,查看单元是否按设计意图工作。程序单元是应用的最小可测试部件。在过程化编程中,一个单元就是单个程序、函数......