该内容为“中国大学MOOC”,华中科技大学《软件测试与质量》第8周单元测试部分的笔记。
IDEA工具可进官网下载,这里使用的2019.3.2版本。
BMI计算程序
新建工程,命名为“HealthIndex”:
在src目录下新建package,“sample.ut”:
在建好的包下新建class,“BMI”:
BMI.java中包含的内容有:
1. 定义属性
private double weight; // 体重
private double height; // 身高
2. getter&setter
在空白处右键,选择“Gennerate”,然后选择“Getter and 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;
}
3. 同时设定所有属性
public void setParams(double w, double h){
this.weight = w;
this.height = h;
}
4. 定义构造方法
public BMI(double w, double h){
this.weight = w;
this.height = h;
}
5. 定义功能方法
public String getBMIType(){
// 1. 初始化
String result = "";
double bmi = 0.0;
if(weight>0 && height>0){
// 2. 计算BMI
bmi = weight / (height*height);
// 3. 判断所属分类
if(bmi<20.5){
result = "偏瘦";
}else if(bmi<24){
result = "正常";
}else if(bmi<28){
result = "偏胖";
}else{
result = "肥胖";
}
}else{
result = "数据有误";
}
// 4. 返回分类结果
return result;
}
使用Junit4创建简单测试方法
创建一个新的文件夹“test”,跟src同层:
右键test文件夹,把它标记为Test Sources Root:
在test文件夹下也建立同名的包“sample.ut”:
回到BMI.java文件中,在空白处右键,选择“Go To” --> “Test”:
创建新的Test:
选择“JUnit4”,勾选下图所示部分:
如果提示没有JUnit4包,点击右边的“Fix”:
在弹出的框中直接点OK即可:
如果导入失败,在导入过程中检查该路径:
发现路径下没有jar包:
可以到IDEA的下载路径的lib文件夹下找到,并copy过来:
创建成功后,在BMITest.java中定义被测对象,并补充测试方法:
BMI testObj;
@Test
public void getBMIType() {
// 创建被测对象
testObj = new BMI(45.0, 1.6);
// 调用测试方法
String actual = testObj.getBMIType();
// 校验测试结果
String except = "偏瘦";
assertTrue(actual==except);
}
完整的BMITest.java内容为:
package sample.ut;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import static org.junit.Assert.*;
public class BMITest {
BMI testObj;
@Before
public void setUp() throws Exception {
}
@After
public void tearDown() throws Exception {
}
@Test
public void getBMIType() {
// 创建被测对象
testObj = new BMI(45.0, 1.6);
// 调用测试方法
String actual = testObj.getBMIType();
// 校验测试结果
String except = "偏瘦";
assertTrue(actual==except);
// 销毁测试对象
testObj = null;
}
}
点击方法前的运行:
测试通过:
修改expect,使其失败,再次运行:
运行失败,可通过控制台查看出错原因。
一次性执行多个测试方法
在上述BMITest.java中,可定义多个测试方法@Test进行测试:
@Test
public void getBMIType1() {
testObj = new BMI(45.0, 1.6);
String actual = testObj.getBMIType();
String except = "偏瘦";
assertTrue(actual==except);
testObj = null;
}
@Test
public void getBMIType2() {
testObj = new BMI(55.0, 1.6);
String actual = testObj.getBMIType();
String except = "正常";
assertTrue(actual==except);
testObj = null;
}
需要注意的是,执行测试的顺序和定义测试的顺序不一定相同,且这样写测试方法会造成冗余。
Junit4提供了以下几种基本注解:
它们的执行顺序如下:
因此,可以在BMITest.java中,在@Before中创建被测对象,在@After中销毁被测对象,减少冗余:
@Before
public void setUp() throws Exception {
testObj = new BMI();
System.out.println("Run @Before method");
}
@After
public void tearDown() throws Exception {
testObj = null;
System.out.println("Run @After method");
}
在BMI.java中添加无参的构造方法:
修改测试方法写法:
@Test
public void getBMIType1() {
testObj.setParams(45.0, 1.6);
// 调用测试方法
String actual = testObj.getBMIType();
// 校验测试结果
String except = "偏瘦";
assertTrue(actual==except);
}
修改后的完整 BMITest.java:
package sample.ut;
// 使用junit4的测试
import org.junit.*;
import static org.junit.Assert.*;
public class BMITest {
BMI testObj;
@Before
public void setUp() throws Exception {
testObj = new BMI();
System.out.println("Run @Before method");
}
@After
public void tearDown() throws Exception {
testObj = 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");
}
@Test
public void getBMIType1() {
System.out.println("Run getBMIType1 method");
testObj.setParams(45.0, 1.6);
// 调用测试方法
String actual = testObj.getBMIType();
// 校验测试结果
String except = "偏瘦";
assertTrue(actual==except);
}
@Test
public void getBMIType2() {
System.out.println("Run getBMIType2 method");
testObj.setParams(55.0, 1.6);
// 调用测试方法
String actual = testObj.getBMIType();
// 校验测试结果
String except = "正常";
assertTrue(actual==except);
}
}
执行结果:
可以清楚的明白注解的执行顺序。
测试参数化
为了使运行多个测试用例的代码简洁,可以使用参数化运行器来进行测试。
org.junit.runners.Parameterized
测试步骤:
- 指定参数化运行器 @RunWith(Parameterized.class)
- 准备测试数据(构造注入or属性注入)
- 添加Test方法,执行测试
构造注入
创建新的测试类BMITestParam.java,创建方法同BMITest.java。
用带参数的构造函数获取数据集,分为以下几个步骤:
1. 定义参数:定义私有变量,用以保存输入和与预期输出。
private double weight; // 体重
private double height; // 身高
private String expected; // 预期分类
2. 引入参数:定义带参数的构造方法。
public BMITestParam(double w, double h, String exp){
this.weight = w;
this.height = h;
this.expected = exp;
}
3. 准备测试数据:定义一个特殊方法。
@Parameterized.Parameters
public static Collection testDataset(){
return Arrays.asList(
new Object[][]{
{45.0, 1.6, "偏瘦"},
{55.0, 1.6, "正常"},
{68.0, 1.6, "偏胖"},
{80.0, 1.6, "肥胖"}
}
);
}
为了使测试结果有更好的可读性,可对Patameters添加内部属性:
在该例中,可改为:
@Parameterized.Parameters(name="{index}:getBMIType[{0},{1}]=[{2}]")
完整的测试代码:
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.*;
// 指定参数化运行器
@RunWith(Parameterized.class)
public class BMITestParam {
BMI testObj; // 定义被测类对象
// 1. 定义参数
private double weight; // 体重
private double height; // 身高
private String expected; // 预期分类
// 2. 引入参数(定义构造方法)
public BMITestParam(double w, double h, String exp){
this.weight = w;
this.height = h;
this.expected = exp;
}
// 3. 准备测试数据
@Parameterized.Parameters(name="{index}:getBMIType[{0},{1}]=[{2}]")
public static Collection testDataset(){
return Arrays.asList(
new Object[][]{
{45.0, 1.6, "偏瘦"},
{55.0, 1.6, "正常"},
{68.0, 1.6, "偏胖"},
{80.0, 1.6, "肥胖"}
}
);
}
@Before
public void setUp() throws Exception {
testObj = new BMI(weight, height);
}
@After
public void tearDown() throws Exception {
testObj = null;
}
@Test
public void getBMIType() {
assertTrue(testObj.getBMIType()==expected);
}
}
运行结果:
属性注入
创建新的测试类BMITestParam2.java,创建方法同BMITest.java。
用属性指定获取数据集,分为以下几个步骤:
1. 定义参数:定义共有变量,用以保存输入和预期输出,并指定每个属性为参数:
@Parameterized.Parameter(0)
public double weight; // 体重
@Parameterized.Parameter(1)
public double height; // 身高
@Parameterized.Parameter(2)
public String expected; // 预期分类
2. 准备测试数据:定义一个特殊方法(同构造注入)。
完整测试代码:
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.*;
// 指定参数化运行器
@RunWith(Parameterized.class)
public class BMITestParam2 {
BMI testObj; // 定义被测类对象
// 1. 定义参数
@Parameterized.Parameter(0)
public double weight; // 体重
@Parameterized.Parameter(1)
public double height; // 身高
@Parameterized.Parameter(2)
public String expected; // 预期分类
// 2. 准备测试数据
@Parameterized.Parameters(name="{index}:getBMIType[{0},{1}]=[{2}]")
public static Collection testDataset(){
return Arrays.asList(
new Object[][]{
{45.0, 1.6, "偏瘦"},
{55.0, 1.6, "正常"},
{68.0, 1.6, "偏胖"},
{80.0, 1.6, "肥胖"}
}
);
}
@Before
public void setUp() throws Exception {
testObj = new BMI(weight, height);
}
@After
public void tearDown() throws Exception {
testObj = null;
}
@Test
public void getBMIType() {
assertTrue(testObj.getBMIType()==expected);
}
}
运行结果: