SpringBoot单元测试+junit单元测试指南

582 阅读2分钟

摘要:本文主要介绍如何使用junit来编写单元测试,包含mock对象的方法和mock静态方法使用案例,提高开发效率。

pom.xml引入依赖包

springboot引入依赖包

<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-test</artifactId>
</dependency>
<dependency>
   <groupId>org.mockito</groupId>
   <artifactId>mockito-inline</artifactId>
   <scope>test</scope>
</dependency>

普通java项目

<!-- junit5 -->
<dependency>
    <groupId>org.junit.jupiter</groupId>
    <artifactId>junit-jupiter</artifactId>
    <version>5.9.2</version>
    <scope>test</scope>
</dependency>

<dependency>
    <groupId>org.junit.vintage</groupId>
    <artifactId>junit-vintage-engine</artifactId>
    <version>5.9.2</version>
    <scope>test</scope>
</dependency>

<dependency>
    <groupId>org.mockito</groupId>
    <artifactId>mockito-core</artifactId>
    <version>4.11.0</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.mockito</groupId>
    <artifactId>mockito-junit-jupiter</artifactId>
    <version>4.11.0</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.mockito</groupId>
    <artifactId>mockito-inline</artifactId>
    <version>4.11.0</version>
    <scope>test</scope>
</dependency>

定义的类

UserEntity

@Data
@TableName("user")
public class UserEntity {

    @TableId
    private String id;

    private String name;

    private String address;

    private Date createTime;
}

UserUtils

作为被mock的静态类

public class UserUtils {

    public static UserEntity getUser(){
        return new UserEntity();
    }

    public static boolean checkName(String name){
        UserEntity userEntity = getUser();
        return userEntity.getName().equals(name);
    }

}

UserService

mock的测试类

@Service
public class UserService {

    @Autowired
    private UserMapper userMapper;

    @SDS("dynamic_member")
    @Transactional(rollbackFor = Exception.class)
    public UserEntity add(UserEntity userEntity) throws Exception{
        userEntity.setId(IdWorker.getIdStr());
        userEntity.setCreateTime(new Date());
        userMapper.insert(userEntity);
        return userEntity;
    }

    public UserEntity getLoginUser(){
        return UserUtils.getUser();
    }

    public boolean checkName(String name){
        boolean result = UserUtils.checkName(name);
        System.out.println(result);
        return result;
    }
}

单元测试

UserServiceTest

@ExtendWith(MockitoExtension.class)
class UserServiceTest {

    /** mock静态类 */
    private static MockedStatic<UserUtils> userUtils;
    /** mock被测试的类 */
    @InjectMocks
    private UserService userService;

    /** mock注入的类 */
    @Mock
    private UserMapper userMapper;

    @BeforeAll
    static void init(){
        userUtils = Mockito.mockStatic(UserUtils.class);
    }

    @Test
    void add() throws Exception {
        // mock方法中调用的其他方法
        Mockito.when(userMapper.insert(Mockito.any())).thenReturn(1);
        UserEntity result = userService.add(new UserEntity());
        assertNotNull(result.getId());
    }

    @Test
    void getLoginUser() {
        UserEntity userEntity = new UserEntity();
        userEntity.setName("zhangsan");
        // mock无参静态方法
        userUtils.when(UserUtils::getUser).thenReturn(userEntity);
        UserEntity result = userService.getLoginUser();
        assertEquals("zhangsan",result.getName());
    }

    @Test
    void checkName() {
        // mock有参数静态方法
        userUtils.when(() -> UserUtils.checkName(Mockito.anyString())).thenReturn(true);
        boolean result = userService.checkName("zhangsan");
        assertTrue(result);

        // mock有参数静态方法
        userUtils.when(() -> UserUtils.checkName(Mockito.anyString())).thenReturn(false);
        result = userService.checkName("zhangsan");
        assertFalse(result);
    }
}

测试结果

符合我们得预期结果

image.png

image.png

使用SpringBoot上下文的单元测试

为什么要使用SpringBoot上下文来测试呢,因为有时候我们需要查询数据库数据,或者测试我们的SQL语句是否正确,我们就需要快速启动Spring来进行验证,这里使用单元测试能更快保证我们的开发速度

使用的注解

@ExtendWith

扩展用于申明是什么类型的单元测试,使用@ExtendWith(SpringExtension.class)

@SpringBootTest

该类用于启动SpringBoot的上下文

  • 如果直接使用@SpringBootTest则会从该类的包从下往上找到SpringBoot的启动类,直接启动全部的模块,速度比较慢
  • 推荐使用@SpringBootTest(classes = Sample2Test.class),使用自己当前的测试类作为启动类

@ComponentScan

需要扫描的包,我们需要什么包就扫描什么包

@Import

我们需要Spring管理的Bean,可以通过这种方式引入,也可以通过上面的包扫描

@ImportAutoConfiguration

导入自动装配,比如rabbitmq@ImportAutoConfiguration(value = {RabbitAutoConfiguration.class}),总之我们需要什么引入什么

@ActiveProfiles("default")

指定单元测试的xxx.yml配置文件

完整案例

@ExtendWith(SpringExtension.class)
@SpringBootTest(classes = Sample2Test.class)
@ComponentScan(value = {"com.huzhihui.rabbitmq.demo.sample"})
@Import(value = {SampleProducer.class})
@ImportAutoConfiguration(value = {RabbitAutoConfiguration.class})
@ActiveProfiles("default")
public class Sample2Test {

    @Autowired
    private SampleProducer sampleProducer;

    @Test
    void testSend() {
        sampleProducer.send("测试2,不要相互影响");
    }

}