SpringBoot中如何使用单元测试

638 阅读3分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第4天,点击查看活动详情

👨‍🎓作者:生无clean

🏦仓库:GithubGitee

✏️博客:CSDN掘金InfoQ云+社区

🙏版权声明:文章里的部分文字或者图片来自于互联网以及百度百科,如有侵权请尽快联系小编。

☠️每日毒鸡汤:好的容貌和很多钱,是进入上流社交活动的通行证。

  • 使用 SpringBoot 开始的时候,肯定是用到单元测试。使用单元测试不同于正常的编写接口等,返回值、依赖注入等都有略微的不同,今天主要就是分享一篇关于单元测试的文章。

单元测试

1.1 单元测试概念

  • 单元测试(unit testing),是指对软件中的最小可测试单元进行检查和验证。在Java中单元测试的最小单元是类。
  • 单元测试是开发者编写的一小段代码,用于检验被测代码的一个很小的、很明确的功能是否正确。执行单元测试,就是为了证明这 段代码的行为和我们期望是否一致。

2.1 SpringBoot中使用单元测试

2.1.1 引入依赖

  • spring框架提供测试模块spring-test,用于应用程序的集成测试,在springboot中,通过spring-boot-starter-test启动器来快速开启和使用。
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-test</artifactId>
  <scope>test</scope>
</dependency>
  • 编写测视类,在项目中的测试包中编写单元测试类

junit单元测试类上要加一些注解,如下:

  • @RunWith就是一个运行器,@RunWith(SpringRunner.class)指让类运行在Spring的测试环境,以便测试开始时自动创建Spring应用上下文。
  • @SpringBootTest替代了spring-test中的@ContextConfiguration注解,目的是加载ApplicationContext,启动spring容器。
  • @ActiveProfiles指定配置环境,我设置了四种环境,开发【dev】、测试【test】、演示【uat】和生产【pro】。在@ActiveProfiles注解上指定对应的配置就会使用对应的配置参数来运行。
/**
 * @description: 项目测试类
 * @author: chengyunbo@gyyx.cn
 * @time: 10:05
 */
@SpringBootTest(classes = WardenApplication.class)
@RunWith(SpringRunner.class)
@ActiveProfiles("dev")
public class TestAlarm {
​
    @Autowired
    AlarmFrequencyUtil alarmFrequencyUtil;
​
    @Test
    public void testAlarm(){
        AlarmLog alarmLog = new AlarmLog();
        alarmLog.setGyyx("AM0346");
        alarmLog.setDetectionId(36);
        if (alarmFrequencyUtil.alarmJudgment(alarmLog)) System.out.println(1);
        else System.out.println(2);
    }
​
}

3. 单元测试注意点

3.1 单元测试方法

  1. 日志记录,最开始已经说明了在junit单元测试方法里面不能直接使用logback,我改用通用类日志LoggerFactory,也可以实现控制台的日志打印。
  2. 在junit单元测试方法上,需要添加注解@Test,他的作用就是该方法可以不用main方法调用就可以测试出运行结果,是一种测试方法。
  3. 在junit测试方法里面可以直接调用service方法或者dao层方法,跟正常的控制类controller里面调用一样。
  4. junit测试方法里面只能调用静态方法。
  5. junit测试方法不能带参,无返回值。

4. 单元测试类中的依赖注入

  • 测试类中依赖注入和普通的业务接口引入依赖有一些区别,有几点需要注意的地方。

4.1 Field 注入(成功)

@Autowired
private UserService userService;
​
@Resource
private UserService userService;

4.2 Setter 方法注入(成功)

/**
 * @description: 项目测试类
 * @author: chengyunbo@gyyx.cn
 * @time: 10:05
 */
@SpringBootTest(classes = WardenApplication.class)
@RunWith(SpringRunner.class)
@ActiveProfiles("dev")
public class TestAlarm {
    
    AlarmFrequencyUtil alarmFrequencyUtil;
​
    @Autowired
    public void setAlarmFrequencyUtil(AlarmFrequencyUtil alarmFrequencyUtil){
        this.alarmFrequencyUtil = alarmFrequencyUtil;
    }
​
    @Test
    public void testAlarm(){
        AlarmLog alarmLog = new AlarmLog();
        alarmLog.setGyyx("AM0346");
        alarmLog.setDetectionId(36);
        if (alarmFrequencyUtil.alarmJudgment(alarmLog)) System.out.println(1);
        else System.out.println(2);
    }
​
}
  • 注意: 使用 setter 注入方式时,需要在set方法上写上 @Autowired或者@Resource注解。

4.3 构造器注入方式(失败)


/**
 * @description: 项目测试类
 * @author: chengyunbo@gyyx.cn
 * @time: 10:05
 */
@SpringBootTest(classes = WardenApplication.class)
@RunWith(SpringRunner.class)
@ActiveProfiles("dev")
public class TestAlarm {
​
    AlarmFrequencyUtil alarmFrequencyUtil;
  
    public TestAlarm(AlarmFrequencyUtil alarmFrequencyUtil){
        this.alarmFrequencyUtil = alarmFrequencyUtil;
    }
​
    @Test
    public void testAlarm(){
        AlarmLog alarmLog = new AlarmLog();
        alarmLog.setGyyx("AM0346");
        alarmLog.setDetectionId(36);
        if (alarmFrequencyUtil.alarmJudgment(alarmLog)) System.out.println(1);
        else System.out.println(2);
    }
}

报错原因

报错分析

  • 单元测试类中,不允许使用带有参数的构造函数,如果使用这种构造器注入的方式,构造函数中必然会存在参数,导致报错。