在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 

IDEA中使用JUnit4测试工具


0. 测试项目结构

上次在   一篇文章中简单的创建了一个测试类,在此详细地向大家介绍几种使用JUnit4进行测试的几种使用方法。

为了以下的描述更直观,先来看一下最终项目的目录结构。

IDEA中使用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 目录,这是我们自己创建的,创建好之后,我们就标记此目录为测试目录,具体步骤方法如下:

IDEA中使用JUnit4测试工具

(看不清就放大IDEA中使用JUnit4测试工具

2.3 创建测试类

以上述的 BMI 类为示范,如果我们为 BMI 类中的 getBMIType() 方法创建测试类,那么需要在 BMI 类代码界面右键选择Generate...或者直接按Alt+Insert组合键调出一个选项卡,如下:

IDEA中使用JUnit4测试工具

选择Test...选项,之后出现如下页面,按照如下步骤操作:

IDEA中使用JUnit4测试工具

上述步骤中需要注意:选择 JUnit4 版本,如果没有 JUnit4 需要的 jar 包,则点击下载稍等一会即可。最后按 OK 按钮创建测试类,会自动创建在 test 文件夹中。

IDEA中使用JUnit4测试工具

2. JUnit4中写测试脚本

2.1 测试脚本的几点要求

  1. 使用JUnit4中常见的注释:
    • @Test: 一个测试方法;
    • @Before: 每一个测试方法之前运行;
    • @After: 每一个测试方法之后运行;
    • @BeforeClass: 所有测试开始之前运行,注意区分@before;
    • @AfterClass: 所有测试结束之后运行,注意区分 @After;
  2. 使用 断言类中的方法进行预期结果与实际结果之间的一致判定。
  3. 指定参数化运行器,实现测试数据的参数化。
  4. 实现测试中的测试用例分类管理,如以等价类划分法和边界值法进行进行分类。
  5. 指定测试套包运行器,实现不同测试类的套包管理。

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.01.6);
        assertSame(BMIType.THIN, bmi.getBMIType());
    }

    @Category({EPTest.class})
    @Test
    public void getBMIType_Normal() {
        System.out.println("Run getBMITypeNormal");
        bmi.setParams(55.01.6);
        assertSame(BMIType.NORMAL, bmi.getBMIType());
    }

    @Category({EPTest.class})
    @Test
    public void getBMIType_SlightlyFat() {
        System.out.println("Run getBMITypeSlightlyFat");
        bmi.setParams(68.01.6);
        assertSame(BMIType.SLIGHTLY_FAT, bmi.getBMIType());
    }

    @Category({EPTest.class})
    @Test
    public void getBMIType_Fat() {
        System.out.println("Run getBMITypeFat");
        bmi.setParams(80.01.6);
        assertSame(BMIType.FAT, bmi.getBMIType());
    }

    @Category({BVTest.class})
    @Test
    public void testGetBMIType_Boundary1() {
        bmi.setParams(47.101.6);
        assertSame(BMIType.THIN, bmi.getBMIType());
    }

    @Category({BVTest.class})
    @Test
    public void testGetBMIType_Boundary2() {
        bmi.setParams(47.371.6);
        assertSame(BMIType.NORMAL, bmi.getBMIType());
    }

    @Category({BVTest.class})
    @Test
    public void testGetBMIType_Boundary3() {
        bmi.setParams(61.181.6);
        assertSame(BMIType.NORMAL, bmi.getBMIType());
    }

    @Category({BVTest.class})
    @Test
    public void testGetBMIType_Boundary4() {
        bmi.setParams(61.451.6);
        assertSame(BMIType.SLIGHTLY_FAT, bmi.getBMIType());
    }

    @Category({BVTest.class})
    @Test
    public void testGetBMIType_Boundary5() {
        bmi.setParams(71.421.6);
        assertSame(BMIType.SLIGHTLY_FAT, bmi.getBMIType());
    }

    @Category({BVTest.class})
    @Test
    public void testGetBMIType_Boundary6() {
        bmi.setParams(71.691.6);
        assertSame(BMIType.FAT, bmi.getBMIType());
    }

    @Category({BVTest.class})
    @Test
    public void testGetBMIType_Boundary7() {
        bmi.setParams(71.941.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 类中点击运行即可观察到测试结果,如下图:

IDEA中使用JUnit4测试工具

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.01.6, BMIType.THIN},
                        {55.01.6, BMIType.NORMAL},
                        {68.01.6, BMIType.SLIGHTLY_FAT},
                        {80.01.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());
    }
}

它的基本步骤已在上述代码中列出,为了更容易查看,我们在此再总结一下:

  1. 指定参数化运行器Parameterized.class,在类上使用注解@RunWith(Parameterized.class);
  2. 定义 私有属性参数,以便于初始化将要测试的类;
  3. 定义带参构造方法,向私有属性传输数据;
  4. 准备测试数据集;
  5. 定义被测试类,测试类的初始化放在@Before方法中;
  6. 在被测方法中只使用一条语句即可: 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.01.6, BMIType.THIN},
                        {55.01.6, BMIType.NORMAL},
                        {68.01.6, BMIType.SLIGHTLY_FAT},
                        {80.01.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中的稍微有些不同:

  1. 指定参数化运行器Parameterized.class,在类上使用注解@RunWith(Parameterized.class);
  2. 定义 公共属性参数,并添加注解@Parameterized.Parameter(下标),其中下标与数据集中的下标对应;
  3. 无须构造方法,直接准备测试数据集;
  4. 定义被测试类,测试类的初始化放在@Before方法中;
  5. 在被测方法中只使用一条语句即可: 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(13085);
        assertSame(BPType.HIGH_NORMAL, bp.getPressureLevel());
    }

    @Category({EPTest.class})
    @Test
    public void getPressureLevel_FirstLevel(){
        bp.setParams(15095);
        assertSame(BPType.LEVEL_ONE, bp.getPressureLevel());
    }

    @Category({EPTest.class})
    @Test
    public void getPressureLevel_SecondLevel(){
        bp.setParams(170105);
        assertSame(BPType.LEVEL_TWO, bp.getPressureLevel());
    }

    @Category({EPTest.class})
    @Test
    public void getPressureLevel_ThirdLevel(){
        bp.setParams(190120);
        assertSame(BPType.LEVEL_THREE, bp.getPressureLevel());
    }

    @Category({BVTest.class})
    @Test
    public void getPressureLevel_Boundary1(){
        bp.setParams(11970);
        assertSame(BPType.NORMAL, bp.getPressureLevel());
    }

    @Category({BVTest.class})
    @Test
    public void getPressureLevel_Boundary2(){
        bp.setParams(12085);
        assertSame(BPType.HIGH_NORMAL, bp.getPressureLevel());
    }

    @Category({BVTest.class})
    @Test
    public void getPressureLevel_Boundary3(){
        bp.setParams(12185);
        assertSame(BPType.HIGH_NORMAL, bp.getPressureLevel());
    }

    @Category({BVTest.class})
    @Test
    public void getPressureLevel_Boundary4(){
        bp.setParams(13985);
        assertSame(BPType.HIGH_NORMAL, bp.getPressureLevel());
    }

    @Category({BVTest.class})
    @Test
    public void getPressureLevel_Boundary5(){
        bp.setParams(14085);
        assertSame(BPType.LEVEL_ONE, bp.getPressureLevel());
    }

    @Category({BVTest.class})
    @Test
    public void getPressureLevel_Boundary6(){
        bp.setParams(14185);
        assertSame(BPType.LEVEL_ONE, bp.getPressureLevel());
    }

    @Category({BVTest.class})
    @Test
    public void getPressureLevel_Boundary7(){
        bp.setParams(15985);
        assertSame(BPType.LEVEL_ONE, bp.getPressureLevel());
    }

    @Category({BVTest.class})
    @Test
    public void getPressureLevel_Boundary8(){
        bp.setParams(16085);
        assertSame(BPType.LEVEL_TWO, bp.getPressureLevel());
    }

    @Category({BVTest.class})
    @Test
    public void getPressureLevel_Boundary9(){
        bp.setParams(17985);
        assertSame(BPType.LEVEL_TWO, bp.getPressureLevel());
    }

    @Category({BVTest.class})
    @Test
    public void getPressureLevel_Boundary10(){
        bp.setParams(18085);
        assertSame(BPType.LEVEL_THREE, bp.getPressureLevel());
    }

    @Category({BVTest.class})
    @Test
    public void getPressureLevel_Boundary11(){
        bp.setParams(18185);
        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中使用JUnit4测试工具

IDEA中使用JUnit4测试工具

以上是关于在IDEA中Java项目如何创建测试类(Junit测试工具)的主要内容,如果未能解决你的问题,请参考以下文章

4-7《Java的调试与优化(IDEA)》——junit单元测试debug调试IDEA常用快捷键

使用JUnit配置IntelliJ IDEA以进行单元测试

IDEA导入JUnit测试类

Intellij IDEA junit 使用之org.junit不存在

如何在没有 Maven 的情况下同时运行 Eclipse Java 项目的所有 JUnit 测试?

IDEA Maven项目中junit测试时无法在控制台输入的解决方法