在IDEA中Java项目如何创建测试类(Junit测试工具)
Posted 卡多莫西
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了在IDEA中Java项目如何创建测试类(Junit测试工具)相关的知识,希望对你有一定的参考价值。
一、导入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
二、在idea中创建包结构
第一步、选择file ----> 然后选择project structure选项
然后会跳转到下图页面
第二步,建立包文件
1,点击New Folder
2, 把包变成Tests包
最终的文件结构:
3,创建测试类
测试类规则:测试类必须和启动类保持一致。
如启动类叫做Application 那么测试类必须叫做ApplicationTests
4 测试类注解和方法
必须在测试类上添加注解@SpringBootTest
测试方法上添加注解@Test
@SpringBootTest
public class ApplicationTests
@Autowired
private IOucNoticeService oucNoticeService;
@Test
public void test01()
List<SysUser> list = oucNoticeService.selectNoticeVoisibleRangeByRoleId(3L);
System.out.println(list.toString());
5,操作测试
点击测试方法右边,点击启动,就可以测试,此时的测试就无须启动tomcat服务器,就可以得到想要的打印输出,通过控制台就能看到。
注意:如果你的项目有多个模块,此时测试类要建立启动类的那个模块,其包的文件结构要和启动类一致,否则就会抱以下的错误 :
java.lang.IllegalStateException: Unable to find a @SpringBootConfiguration, you need to use
其错误原因就是:试类的包名与启动器的包名不一致
解决方法:Spring Boot测试类包名与main下application.class启动类的包名默认要一致,并且包的结构也要一直,要修改包名和包的结构后问题得以解决!
如启动类叫做Application.class 那么测试类必须叫做ApplicationTests.class
如图所示:
IDEA中使用JUnit4测试工具
“ 搞了一天测试,人已die ”
0. 测试项目结构
上次在 一篇文章中简单的创建了一个测试类,在此详细地向大家介绍几种使用JUnit4进行测试的几种使用方法。
为了以下的描述更直观,先来看一下最终项目的目录结构。
对上述目录结构的几点说明:
-
在 src 目录下写正常的 Java 类和功能方法,如上述在 sample.ut 包中的 Java 类; -
在项目文件下创建 test 目录, 并标记此目录为测试目录; -
当我们要对某个 Java 类进行测试的时候,可以直接创建测试类,选择要测试的方法,它会自动添加在 test 目录下。
1. 编写 Java 类
看完上述的目录结构,再来具体描述以下创建测试的过程与步骤。为了更好的描述测试过程与步骤细节,在此用一个测试实例来进行描述与讲解。先来看一下这几个具体测试类的功能以及源代码。
1.1 计算 BMI
BMI:身体质量指数是 BMI 指数(身体质量指数,简称体质指数),是目前国际上常用的衡量人体胖瘦程度以及是否健康的一个标准。
BMIType
枚举类:
package sample.ut;
/**
* BMI 类型
*
* @Date: 2020/4/28 14:15
* @author: Eric
*/
public enum BMIType {
// 偏瘦
THIN,
// 正常
NORMAL,
// 偏胖
SLIGHTLY_FAT,
// 肥胖
FAT
}
BMI
类,它的功能是根据体重和身高判断所属的健康分类,源代码如下:
package sample.ut;
/**
* 该类的功能是根据体重和身高判断所属健康分类
*
* @Date: 2020/4/28 11:41
* @author: Eric
*/
public class BMI {
private double weight; // 体重
private double height; // 身高
// 构造方法
public BMI() {
weight = 0.0;
height = 1.0;
}
public BMI(double weight, double height) {
this.weight = weight > 0 ? weight : 0.0;
this.height = height > 0 ? height : 1.0;
}
// getter 和 setter 方法
public double getWeight() {
return weight;
}
public void setWeight(double weight) {
this.weight = weight;
}
public double getHeight() {
return height;
}
public void setHeight(double height) {
this.height = height;
}
// 设置参数
public void setParams(double weight, double height) {
this.weight = weight > 0 ? weight : 0.0;
this.height = height > 0 ? height : 1.0;
}
/**
* 计算BMI值,返回BMI类型
*
* @return BMI类型
*/
public BMIType getBMIType() {
double bmi = weight / (height * height);
if (bmi < 18.5) {
return BMIType.THIN;
} else if (bmi < 24) {
return BMIType.NORMAL;
} else if (bmi < 28) {
return BMIType.SLIGHTLY_FAT;
} else {
return BMIType.FAT;
}
}
}
1.2 计算血压值类型
血压类型——BPType
枚举类,代码如下:
package sample.ut;
/**
* 血压类型
*
* @Date: 2020/4/28 16:15
* @author: Eric
*/
public enum BPType {
// 正常值
NORMAL,
// 正常高值
HIGH_NORMAL,
// 一级高血压
LEVEL_ONE,
// 二级高血压
LEVEL_TWO,
// 三级高血压
LEVEL_THREE,
// 异常值
ABNORMAL
}
BloodPressure
类,它的功能是根据收缩压和舒张压的值判断具体的血压类型,源代码如下:
package sample.ut;
/**
* 根据血压值判断血压分级
*
* @Date: 2020/4/28 12:40
* @author: Eric
*/
public class BloodPressure {
private int sys; // 收缩压 systolicPressure
private int dia; // 舒张压 diastolicPressure
// 构造方法
public BloodPressure() {
sys = 0;
dia = 0;
}
public BloodPressure(int sys, int dia) {
this.sys = sys;
this.dia = dia;
}
// getter 和 setter 方法
public int getSys() {
return sys;
}
public void setSys(int sys) {
this.sys = sys;
}
public int getDia() {
return dia;
}
public void setDia(int dia) {
this.dia = dia;
}
// 设置参数
public void setParams(int sys, int dia) {
this.sys = sys;
this.dia = dia;
}
public BPType getPressureLevel() {
if (sys < 120 && dia < 80) {
return BPType.NORMAL;
}
if ((sys >= 120 && sys <= 139) && (dia >= 80 && dia <= 89)) {
return BPType.HIGH_NORMAL;
}
if ((sys >= 140 && sys <= 159) || (dia >= 90 && dia <= 99)) {
return BPType.LEVEL_ONE;
}
if ((sys >= 160 && sys <= 179) || (dia >= 100 && dia <= 109)) {
return BPType.LEVEL_TWO;
}
if (sys >= 180 || dia >= 110) {
return BPType.LEVEL_THREE;
}
return BPType.ABNORMAL;
}
}
2. 创建测试目录和测试类
2.1 创建测试目录
一开始创建项目时并没有 test 目录,这是我们自己创建的,创建好之后,我们就标记此目录为测试目录,具体步骤方法如下:
(看不清就放大)
2.3 创建测试类
以上述的 BMI 类为示范,如果我们为 BMI 类中的 getBMIType()
方法创建测试类,那么需要在 BMI 类代码界面右键选择Generate...
或者直接按Alt+Insert
组合键调出一个选项卡,如下:
选择Test...
选项,之后出现如下页面,按照如下步骤操作:
上述步骤中需要注意:选择 JUnit4 版本,如果没有 JUnit4 需要的 jar 包,则点击下载稍等一会即可。最后按 OK 按钮创建测试类,会自动创建在 test 文件夹中。
2. JUnit4中写测试脚本
2.1 测试脚本的几点要求
-
使用JUnit4中常见的注释: -
@Test: 一个测试方法; -
@Before: 每一个测试方法之前运行; -
@After: 每一个测试方法之后运行; -
@BeforeClass: 所有测试开始之前运行,注意区分@before; -
@AfterClass: 所有测试结束之后运行,注意区分 @After; -
使用 断言类中的方法进行预期结果与实际结果之间的一致判定。 -
指定参数化运行器,实现测试数据的参数化。 -
实现测试中的测试用例分类管理,如以等价类划分法和边界值法进行进行分类。 -
指定测试套包运行器,实现不同测试类的套包管理。
2.2 BMITest类的源代码
对上述自动生成的BMITest
测试类,我们在里边编写以下代码:
package sample.ut;
import org.junit.*;
import org.junit.experimental.categories.Category;
import static org.junit.Assert.*;
public class BMITest {
BMI bmi;
@Before
public void setUp() throws Exception {
bmi = new BMI();
System.out.println("Run @Before method");
}
@After
public void tearDown() throws Exception {
bmi = null;
System.out.println("Run @After method");
}
@BeforeClass
public static void prepareEnvironment() {
System.out.println("Run @BeforeClass method");
}
@AfterClass
public static void restoreEnvironment() {
System.out.println("Run @AfterClass method");
}
@Category({EPTest.class})
@Test
public void getBMIType_Thin() {
System.out.println("Run getBMITypeThin");
bmi.setParams(45.0, 1.6);
assertSame(BMIType.THIN, bmi.getBMIType());
}
@Category({EPTest.class})
@Test
public void getBMIType_Normal() {
System.out.println("Run getBMITypeNormal");
bmi.setParams(55.0, 1.6);
assertSame(BMIType.NORMAL, bmi.getBMIType());
}
@Category({EPTest.class})
@Test
public void getBMIType_SlightlyFat() {
System.out.println("Run getBMITypeSlightlyFat");
bmi.setParams(68.0, 1.6);
assertSame(BMIType.SLIGHTLY_FAT, bmi.getBMIType());
}
@Category({EPTest.class})
@Test
public void getBMIType_Fat() {
System.out.println("Run getBMITypeFat");
bmi.setParams(80.0, 1.6);
assertSame(BMIType.FAT, bmi.getBMIType());
}
@Category({BVTest.class})
@Test
public void testGetBMIType_Boundary1() {
bmi.setParams(47.10, 1.6);
assertSame(BMIType.THIN, bmi.getBMIType());
}
@Category({BVTest.class})
@Test
public void testGetBMIType_Boundary2() {
bmi.setParams(47.37, 1.6);
assertSame(BMIType.NORMAL, bmi.getBMIType());
}
@Category({BVTest.class})
@Test
public void testGetBMIType_Boundary3() {
bmi.setParams(61.18, 1.6);
assertSame(BMIType.NORMAL, bmi.getBMIType());
}
@Category({BVTest.class})
@Test
public void testGetBMIType_Boundary4() {
bmi.setParams(61.45, 1.6);
assertSame(BMIType.SLIGHTLY_FAT, bmi.getBMIType());
}
@Category({BVTest.class})
@Test
public void testGetBMIType_Boundary5() {
bmi.setParams(71.42, 1.6);
assertSame(BMIType.SLIGHTLY_FAT, bmi.getBMIType());
}
@Category({BVTest.class})
@Test
public void testGetBMIType_Boundary6() {
bmi.setParams(71.69, 1.6);
assertSame(BMIType.FAT, bmi.getBMIType());
}
@Category({BVTest.class})
@Test
public void testGetBMIType_Boundary7() {
bmi.setParams(71.94, 1.6);
assertSame(BMIType.FAT, bmi.getBMIType());
}
}
在上述代码中,每使用了@Test的注解的都为一个测试方法,对应一个测试用例,在每个测试方法执行之前,会先运行使用@Before注解的方法,在每个测试方法执行结束之后,运行@After注解之后的方法。
我们发现在上述代码中使用了注解@Category({EPTest.class})
和@Category({BVTest.class})
,这是两个标记,用以标记此测试方法是等价类测试用例还是边界值测试用例。其中的EPTest和BVTest是两个接口,这两个接口也是创建在测试目录下的,其源代码如下:
package sample.ut;
/**
* 等价类测试用例标签
*
* @Date: 2020/4/28 15:33
* @author: Eric
*/
public interface EPTest {
}
package sample.ut;
/**
* 边界值测试用例标签
*
* @Date: 2020/4/28 12:55
* @author: Eric
*/
public interface BVTest {
}
我们在 BMITest 类中点击运行即可观察到测试结果,如下图:
2.3 使用参数化运行器1
上述测试代码过于繁杂,为了更简洁的测试我们的 BMI 类中的 getBMIType()
方法,我们可以使用参数化运行器。同样我们要创建一个测试类,方法同上,此时我们命名为:BMITestParam1
。
源代码如下:
package sample.ut;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import java.util.Arrays;
import java.util.Collection;
import static org.junit.Assert.*;
// 1.指定参数化运行器Parameterized.class
@RunWith(Parameterized.class)
public class BMITestParam1 {
// 2.定义私有属性参数
private double weight;
private double height;
private BMIType expected;
// 3.定义带参构造方法,向私有属性传输数据
public BMITestParam1(double weight, double height, BMIType expected) {
this.weight = weight;
this.height = height;
this.expected = expected;
}
// 4.准备测试数据集
@Parameterized.Parameters(name = "{index}:getBMIType[{0},{1}]=[{2}]")
public static Collection testDataSet() {
return Arrays.asList(
new Object[][]{
{45.0, 1.6, BMIType.THIN},
{55.0, 1.6, BMIType.NORMAL},
{68.0, 1.6, BMIType.SLIGHTLY_FAT},
{80.0, 1.6, BMIType.FAT}
}
);
}
// 5.定义被测试类
BMI bmi;
@Before
public void setUp() throws Exception {
bmi = new BMI(weight, height); // 初始化
}
@After
public void tearDown() throws Exception {
bmi = null;
}
@Test
public void getBMIType() {
assertSame(expected, bmi.getBMIType());
}
}
它的基本步骤已在上述代码中列出,为了更容易查看,我们在此再总结一下:
-
指定参数化运行器Parameterized.class,在类上使用注解@RunWith(Parameterized.class); -
定义 私有属性参数,以便于初始化将要测试的类; -
定义带参构造方法,向私有属性传输数据; -
准备测试数据集; -
定义被测试类,测试类的初始化放在@Before方法中; -
在被测方法中只使用一条语句即可: assertSame(expected, bmi.getBMIType());
。
2.4 使用参数化运行器2
除了像参数化运行器1中使用了构造方法向私有属性中注入值,我们还可以直接向属性中注入值,源代码如下:
package sample.ut;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import java.util.Arrays;
import java.util.Collection;
import static org.junit.Assert.*;
// 1.指定参数化运行器
@RunWith(Parameterized.class)
public class BMITestParam2 {
// 2.定义属性,注入参数,参数必须public类型
@Parameterized.Parameter(0)
public double weight; // 体重
@Parameterized.Parameter(1)
public double height; // 身高
@Parameterized.Parameter(2)
public BMIType expected; // 预期类别
// 3.准备测试数据集
@Parameterized.Parameters(name = "{index}:getBMIType[{0},{1}]=[{2}]")
public static Collection testDataset() {
return Arrays.asList(
new Object[][]{
{45.0, 1.6, BMIType.THIN},
{55.0, 1.6, BMIType.NORMAL},
{68.0, 1.6, BMIType.SLIGHTLY_FAT},
{80.0, 1.6, BMIType.FAT}
}
);
}
// 4.定义被测试类
BMI bmi;
@Before
public void setUp() throws Exception {
bmi = new BMI(weight, height); // 初始化
}
@After
public void tearDown() throws Exception {
bmi = null;
}
@Test
public void getBMIType() {
assertSame(expected,bmi.getBMIType());
}
}
步骤和参数化运行器1中的稍微有些不同:
-
指定参数化运行器Parameterized.class,在类上使用注解@RunWith(Parameterized.class); -
定义 公共属性参数,并添加注解@Parameterized.Parameter(下标),其中下标与数据集中的下标对应; -
无须构造方法,直接准备测试数据集; -
定义被测试类,测试类的初始化放在@Before方法中; -
在被测方法中只使用一条语句即可: assertSame(expected, bmi.getBMIType());
。
2.5 分类测试
我们在 BMITest 类中为每个测试方法都打上了不同的标签,那么我们如何把它们分开测试呢?同样是创建测试类,如下测试类代码演示了只运行 BMITest 中的边界值测试用例:
package sample.ut;
import org.junit.experimental.categories.Categories;
import org.junit.runner.RunWith;
import org.junit.runners.Suite;
// 测试同一测试类中的不同特性
// 指定运行器Categories.class
// 设置要运行的测试特性BVTest.class
// 设置候选测试集BMITest.class
@RunWith(Categories.class)
@Categories.IncludeCategory({BVTest.class})
@Suite.SuiteClasses({BMITest.class})
public class CategoryTest {
// 运行即执行BMITest、BloodPressureTest中带有BVTest标签的测试方法
}
2.6 套包测试
我们先为BloodPressure类创建一个测试类 BloodPressureTest,代码如下:
package sample.ut;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import static org.junit.Assert.*;
public class BloodPressureTest {
// 定义被测试类
BloodPressure bp;
@Before
public void setUp() throws Exception {
bp = new BloodPressure();
}
@After
public void tearDown() throws Exception {
bp = null;
}
@Test
public void getPressureLevel() {
}
@Category({EPTest.class})
@Test
public void getPressureLevel_Normal() {
bp.setParams(100,70);
assertSame(BPType.NORMAL, bp.getPressureLevel());
}
@Category({EPTest.class})
@Test
public void getPressureLevel_NormalHigher() {
bp.setParams(130, 85);
assertSame(BPType.HIGH_NORMAL, bp.getPressureLevel());
}
@Category({EPTest.class})
@Test
public void getPressureLevel_FirstLevel(){
bp.setParams(150, 95);
assertSame(BPType.LEVEL_ONE, bp.getPressureLevel());
}
@Category({EPTest.class})
@Test
public void getPressureLevel_SecondLevel(){
bp.setParams(170, 105);
assertSame(BPType.LEVEL_TWO, bp.getPressureLevel());
}
@Category({EPTest.class})
@Test
public void getPressureLevel_ThirdLevel(){
bp.setParams(190, 120);
assertSame(BPType.LEVEL_THREE, bp.getPressureLevel());
}
@Category({BVTest.class})
@Test
public void getPressureLevel_Boundary1(){
bp.setParams(119, 70);
assertSame(BPType.NORMAL, bp.getPressureLevel());
}
@Category({BVTest.class})
@Test
public void getPressureLevel_Boundary2(){
bp.setParams(120, 85);
assertSame(BPType.HIGH_NORMAL, bp.getPressureLevel());
}
@Category({BVTest.class})
@Test
public void getPressureLevel_Boundary3(){
bp.setParams(121, 85);
assertSame(BPType.HIGH_NORMAL, bp.getPressureLevel());
}
@Category({BVTest.class})
@Test
public void getPressureLevel_Boundary4(){
bp.setParams(139, 85);
assertSame(BPType.HIGH_NORMAL, bp.getPressureLevel());
}
@Category({BVTest.class})
@Test
public void getPressureLevel_Boundary5(){
bp.setParams(140, 85);
assertSame(BPType.LEVEL_ONE, bp.getPressureLevel());
}
@Category({BVTest.class})
@Test
public void getPressureLevel_Boundary6(){
bp.setParams(141, 85);
assertSame(BPType.LEVEL_ONE, bp.getPressureLevel());
}
@Category({BVTest.class})
@Test
public void getPressureLevel_Boundary7(){
bp.setParams(159, 85);
assertSame(BPType.LEVEL_ONE, bp.getPressureLevel());
}
@Category({BVTest.class})
@Test
public void getPressureLevel_Boundary8(){
bp.setParams(160, 85);
assertSame(BPType.LEVEL_TWO, bp.getPressureLevel());
}
@Category({BVTest.class})
@Test
public void getPressureLevel_Boundary9(){
bp.setParams(179, 85);
assertSame(BPType.LEVEL_TWO, bp.getPressureLevel());
}
@Category({BVTest.class})
@Test
public void getPressureLevel_Boundary10(){
bp.setParams(180, 85);
assertSame(BPType.LEVEL_THREE, bp.getPressureLevel());
}
@Category({BVTest.class})
@Test
public void getPressureLevel_Boundary11(){
bp.setParams(181, 85);
assertSame(BPType.LEVEL_THREE, bp.getPressureLevel());
}
}
现在我们想同时执行 BMITest 和 BloodPressureTest ,怎么办呢?这时候我们就需要用到套包测试了,此时需要用到运行器Suite
,具体测试代码如下:
package sample.ut;
import org.junit.runner.RunWith;
import org.junit.runners.Suite;
// 套包测试
// 指定运行器 Suite.class,指定要加入的测试类 BMITest 和 BloodPressureTest
@RunWith(Suite.class)
@Suite.SuiteClasses({BMITest.class,BloodPressureTest.class})
public class TestSuiteWithBMIAndBP {
// 运行即执行 BMITest、BloodPressureTest 测试类
}
上述代码直接运行,就可以实现两个测试类同时执行了。
以上是关于在IDEA中Java项目如何创建测试类(Junit测试工具)的主要内容,如果未能解决你的问题,请参考以下文章 4-7《Java的调试与优化(IDEA)》——junit单元测试debug调试IDEA常用快捷键 Intellij IDEA junit 使用之org.junit不存在