JUnit——Java单元测试框架
程序员文章站
2024-03-15 19:41:54
...
概述
JUnit由Kent Beck和Erich Gamma建立,逐渐成为源于Kent Beck的sUnit的xUnit家族中最为成功的一个。
优点
- 极限编程
基本过程:构思-> 编写测试代码-> 编写代码-> 测试,而且编写测试和编写代码都是增量式的,写一点测一点,在编写以后的代码中如果发现问题可以较快的追踪到问题的原因,减小回归错误的纠错难度。 - 重构
其好处和极限编程中是类似的,因为重构也是要求改一点测一点,减少回归错误造成的时间消耗。
特性
- 用于测试期望结果的断言(Assertion)
- 用于共享共同测试数据的测试工具
- 用于方便的组织和运行测试的测试套件
- 图形和文本的测试运行器
用法示例
题目——BMI:
被测对象BMI类:
public class BMI {
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 w, double h){
this.weight = w;
this.height = h;
}
public BMI(double w,double h){
this.weight = w;
this.height = h;
}
public BMI(){
this.weight = 0.0;
this.height = 0.0;
}
public String getBMIType(){
double bmi = 0.0;
String result = "";
if(weight>0 && height >0 ){
bmi = weight/(height*height);
if(bmi<18.5){
result = "偏瘦";
}else if(bmi<24){
result = "正常";
} else if (bmi < 28) {
result = "偏肥";
}else {
result = "肥胖";
}
}else{
return "Weight or height error!";
}
return result;
}
double weight;
double height;
}
题目——BloodPressure:
被测对象BloodPressure类:
public class BloodPressure {
public int getSystolicPressure() {
return systolicPressure;
}
public void setSystolicPressure(int systolicPressure) {
this.systolicPressure = systolicPressure;
}
public int getDiatolicPressure() {
return diatolicPressure;
}
public void setDiatolicPressure(int diatolicPressure) {
this.diatolicPressure = diatolicPressure;
}
public void setParams(int systolicPressure,int diatolicPressure){
this.systolicPressure = systolicPressure;
this.diatolicPressure = diatolicPressure;
}
public BloodPressure(){
systolicPressure = 0;
diatolicPressure = 0;
}
public BloodPressure(int systolicPressure,int diatolicPressure){
this.systolicPressure = systolicPressure;
this.diatolicPressure = diatolicPressure;
}
public String getPressureLevel() {
if(systolicPressure < 120 && diatolicPressure < 80){
return "正常";
}else if(systolicPressure<= 139 && diatolicPressure <= 89){
return "正常高值";
}else if(systolicPressure <= 159 || diatolicPressure <= 99)
{
return "1级高血压";
}else if(systolicPressure <= 179 || diatolicPressure <= 109){
return "2级高血压";
}else {
return "3级高血压";
}
}
int systolicPressure; //收缩压
int diatolicPressure; //舒张压
}
测试用例独立执行
测试用例的执行顺序:
- @Before,在每个测试用例执行之前执行一次
- @After,在每个测试用例执行之后执行一次
- @BeforeClass,在测试类的所有测试用例执
行之前执行一次 - @AfterClass,在测试类的所有测试用例执行
之后执行一次
独立执行:
public class BMITest {
BMI testObj;
@Before
public void setUp(){
System.out.println("Run @Before method");
testObj = new BMI();
}
@After
public void tearDown(){
System.out.println("Run @After method");
testObj = null;
}
@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 testGetBMIType_Thin(){
System.out.println("Run testGetBMIType_Thin");
testObj.setParams(45.0,1.6);
String expected = "偏瘦";
assertTrue(testObj.getBMIType().equals(expected));
}
@Test
public void testGetBMIType_Normal(){
System.out.println("Run testGetBMIType_Normal");
testObj.setParams(55.0,1.6);
String expected = "正常";
assertTrue(testObj.getBMIType().equals(expected));
}
@Test
public void testGetBMIType_SlightFat(){
System.out.println("Run testGetBMIType_SlightFat");
testObj.setParams(68.0,1.6);
String expected = "偏肥";
assertTrue(testObj.getBMIType().equals(expected));
}
@Test
public void testGetBMIType_Fat(){
System.out.println("Run testGetBMIType_Fat");
testObj.setParams(80.0,1.6);
String expected = "肥胖";
assertTrue(testObj.getBMIType().equals(expected));
}
}
构造注入
- 指定参数化运行器
- 准备测试数据(构造器注入)
2.1 定义参数:定义私有变量,用于保存输入和预期输出
2.2 引入参数:定义带参数的构造方法
2.3 准备测试数据:定义一个特殊方法 - 添加test方法,执行测试
@RunWith(Parameterized.class)
public class BMITestParam {
private double weightForTest;
private double heightForTest;
private String expected;
BMI testObj;
public BMITestParam(double w, double h ,String exp){
weightForTest = w;
heightForTest = h;
expected = exp;
}
@Parameterized.Parameters
public static Collection testData(){
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(weightForTest,heightForTest);
}
@After
public void tearDown(){
testObj = null;
}
@Test
public void testGetBMIType(){
assertTrue(expected.equals(testObj.getBMIType()));
}
}
提高输出结果的可读性:
属性注入
属性注入的方法有点类似构造注入。
@RunWith(Parameterized.class)
public class BMITestParam2 {
BMI testObj;
@Before
public void setUp() throws Exception {
testObj = new BMI(weightForTest,heightForTest);
}
@After
public void tearDown() throws Exception {
testObj = null;
}
@Parameterized.Parameter(0)
public double weightForTest;
@Parameterized.Parameter(1)
public double heightForTest;
@Parameterized.Parameter(2)
public String expected;
@Parameterized.Parameters
public static Collection testData(){
return Arrays.asList(new Object[][]{
{45.0,1.6,"偏瘦"},
{55.0,1.6,"正常"},
{68.0,1.6,"偏肥"},
{80.0,1.6,"肥胖"}
});
}
@Test
public void testGetBMIType(){
assertTrue(expected.equals(testObj.getBMIType()));
}
使用构造注入和属性注入的方法就比逐个编写测试用例的方法简洁多了~
构件测试集
为了能够一次运行多个测试类,JUnit提供了测试集(test suite),这是通过类org.junit.runners.Suite 来实现的。Suite类是一个包含不同测试类的容器,同时也是一个运行器,可以运行一个或多个测试类中,或者多个测试集中的所有用@Test 标注的测试方法。当单独运行一个测试类时,不需要为测试类指定测试集信息,因为测试运行器会自动创建一个Suite。
构建测试集运行BMI和BloodPressure的测试类:
以下为BloodPressure的测试类:
@RunWith(Parameterized.class)
public class BloodPressureTest {
private int sysPressure;
private int diaPressure;
private String expected;
BloodPressure testObj;
public BloodPressureTest(int s,int d,String exp){
sysPressure = s;
diaPressure = d;
expected = exp;
}
@Parameterized.Parameters(name = "{index}:getPressureLevel[{0},{1}={2}]")
public static Collection testData(){
return Arrays.asList(new Object[][]{
{100,70,"正常"},
{130,85,"正常高值"},
{150,95,"1级高血压"},
{170,105,"2级高血压"},
{190,120,"3级高血压"}
});
}
@Before
public void setUp() throws Exception {
testObj = new BloodPressure(sysPressure,diaPressure);
}
@After
public void tearDown() throws Exception {
testObj = null;
}
@Test
public void getPressureLevel(){
assertTrue(testObj.getPressureLevel().equals(expected));
}
}
测试集如下,只需运行下面这个测试类即可:
import org.junit.runner.RunWith;
import org.junit.runners.Suite;
@RunWith(Suite.class)
@Suite.SuiteClasses({BMITestParam2.class,BloodPressureTest.class})
public class TestSuiteWithBMIAndBloodPressure {
}