JUnit4简单使用与进阶
测试场景
测试一个图形是不是三角形,需考虑到三角形的性质要求。除了满足A B C均是正数且大于0,还需满足A>0,B>0,C>0,且A+B>C,B+C>A,A+C>B。
如果是等腰的,还要判断A=B,或B=C,或A=C。
如果是等边的,则需判断是否A=B,且B=C,且A=C。
用JUnit工具和覆盖率分析工具(JaCoCo)完成两个类(一个类的多个方法)的单元测试及其分析,尽量做到语句和分支的100%覆盖。项目中使用JUnit测试框架,包含被测类’Triangle’和测试类’TriangleTest’。然后在使用了JUnit测试框架的项目中使用JaCoCo测试覆盖率。
测试用例
输入条件 | 有效等价类 | 无效等价类 |
---|---|---|
是否三角形的三条边 | (A>0), (1) (B>0), (2) (C>0) (3) (A+B>C)(4) (B+C>A)(5) (A+C>B)(6) | (A≤0), (7) (B≤0), (8) (C≤0), (9) (A+B≤C), (10) (B+C≤A), (11) (A+C≤B), (12) |
是否等腰角形 | (A=B), (13) (B=C), (14) (C=A), (15) | (A≠B)and(B≠C)and(C≠A) (16) |
是否等边三角形 | (A=B)and(B=C)and(C=A) (17) | (A≠B), (18) (B≠C), (19) (C≠A), (20) |
序号 | 【A,B,C】 | 覆盖等价类 | 输出 |
---|---|---|---|
1 | 【3,4,5】 | (1),(2),(3),(4),(5),(6) | 一般三角形 |
2 | 【0,1,2】 | (7) | 不能构成三角形 |
3 | 【1,0,2】 | (8) | 不能构成三角形 |
4 | 【1,2,0】 | (9) | 不能构成三角形 |
5 | 【1,2,3】 | (10) | 不能构成三角形 |
6 | 【1,3,2】 | (11) | 不能构成三角形 |
7 | 【3,1,2】 | (12) | 不能构成三角形 |
8 | 【3,3,4】 | (1),(2),(3),(4),(5),(6),(13) | 等腰三角形 |
9 | 【3,4,4】 | (1),(2),(3),(4),(5),(6),(14) | 等腰三角形 |
10 | 【3,4,3】 | (1),(2),(3),(4),(5),(6),(15) | 等腰三角形 |
11 | 【3,4,5】 | (1),(2),(3),(4),(5),(6),(16) | 非等腰三角形 |
12 | 【3,3,3】 | (1),(2),(3),(4),(5),(6),(17) | 是等边三角形 |
13 | 【3,4,4】 | (1),(2),(3),(4),(5),(6),(14),(18) | 非等边三角形 |
14 | 【3,4,3】 | (1),(2),(3),(4),(5),(6),(15),(19) | 非等边三角形 |
15 | 【3,3,4】 | (1),(2),(3),(4),(5),(6),(13),(20) | 非等边三角形 |
Junit4安装
所需依赖包
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.1</version>
<scope>compile</scope>
</dependency>
测试代码
Triangle.java
package course;
/**
* @author zouran
* createDate:2024/4/16 13:25
*/
public class Triangle {
double a, b, c = 0.0;
public Triangle(double a, double b, double c) {
this.a = a;
this.b = b;
this.c = c;
}
public boolean isTriangle() {
boolean result = false;
if (a > 0 && b > 0 && c > 0) {
if ((a + b > c) && (a + c > b) && (b + c > a)) {
result = true;
}
}
return result;
}
public boolean isIsoscelesTriangle() {
return (a == b) || (a == c) || (b == c);
}
public boolean isEquilateralTriangle() {
return a == b && b == c;
}
}
TriangleTest.java
package course;
import org.junit.*;
/**
* @author zouran
* createDate:2024/4/16 13:26
*/
public class TriangleTest {
@BeforeClass
public static void beforeClassTriangle(){
// System.out.println("beforeClass");
}
@Before
public void beforeTriangle(){
// System.out.println("before");
}
@AfterClass
public static void afterClassTriangle(){
// System.out.println("afterClass");
}
@After
public void afterTriangle(){
// System.out.println("after");
}
@Test
public void testTriangle(){
// System.out.println("三角形");
Assert.assertTrue("是三角形",new Triangle(3,4,5).isTriangle());
Assert.assertFalse("不是三角形",new Triangle(0,1,2).isTriangle());
Assert.assertFalse("不是三角形",new Triangle(1,0,2).isTriangle());
Assert.assertFalse("不是三角形",new Triangle(1,2,0).isTriangle());
Assert.assertFalse("不是三角形",new Triangle(1,2,3).isTriangle());
Assert.assertFalse("不是三角形",new Triangle(1,3,2).isTriangle());
Assert.assertFalse("不是三角形",new Triangle(3,1,2).isTriangle());
}
@Test
public void testIsoscelesTriangle(){
// System.out.println("等腰三角形");
Assert.assertTrue("是等腰三角形",new Triangle(3,3,4).isIsoscelesTriangle());
Assert.assertTrue("是等腰三角形",new Triangle(3,4,4).isIsoscelesTriangle());
Assert.assertTrue("是等腰三角形",new Triangle(3,4,3).isIsoscelesTriangle());
Assert.assertFalse("不是等腰三角形",new Triangle(3,4,5).isIsoscelesTriangle());
}
@Test
public void testIsEquilateralTriangle(){
// System.out.println("等边三角形");
Assert.assertTrue("是等边三角形",new Triangle(3,3,3).isEquilateralTriangle());
Assert.assertFalse("不是等边三角形",new Triangle(3,4,4).isEquilateralTriangle());
Assert.assertFalse("不是等边三角形",new Triangle(3,4,3).isEquilateralTriangle());
Assert.assertFalse("不是等边三角形",new Triangle(3,3,4).isEquilateralTriangle());
}
}
使用Junit4+JaCoCo
覆盖率测试
测试结果
代码覆盖率100%,分支覆盖率100%
测试代码改进
在上述测试用例代码中,测试用例均在代码中书写,当测试用例很多时容易导致极大不便性,鉴于此,将测试用例存储于Excel中,在开始测试前读取Excel数据,Excel中每一列对应测试参数,每个Sheet对应一个方法,我们约束sheet名与方法名一致,实现更便捷与便于修改测试用例的需求
读取Excel文件所需依赖
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>5.2.2</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>5.2.2</version>
</dependency>
改进后代码
TriangleTest.java
package course;
import org.apache.poi.EncryptedDocumentException;
import org.apache.poi.ss.usermodel.*;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @author zouran
* createDate:2024/4/24 13:52
*/
public class TriangleTest {
private static final Map<String, List<Map<String, String>>> data = new HashMap<>();
private static final String excelFilePath = "D:\\projects\\java\\study\\SoftwareIV\\src\\test\\resources\\course\\TriangleTest.xlsx";
@BeforeClass
public static void load_data() {
try (FileInputStream fis = new FileInputStream(excelFilePath);
Workbook workbook = WorkbookFactory.create(fis)) {
for (int i = 0; i < workbook.getNumberOfSheets(); i++) {
// 获取第一个工作表
Sheet sheet = workbook.getSheetAt(i);
if (sheet.getLastRowNum() == -1)
continue;
// 获取列名
Row headerRow = sheet.getRow(0);
List<Map<String, String>> sheet_data = new ArrayList<>();
String[] columnNames = new String[headerRow.getLastCellNum()];
for (int j = 0; j < headerRow.getLastCellNum(); j++) {
Cell cell = headerRow.getCell(j);
columnNames[j] = cell.getStringCellValue();
}
// 遍历数据
for (int rowIndex = 1; rowIndex <= sheet.getLastRowNum(); rowIndex++) {
Row row = sheet.getRow(rowIndex);
Map<String, String> row_data = new HashMap<>();
if (row != null) {
// 遍历每一列
for (int columnIndex = 0; columnIndex < row.getLastCellNum(); columnIndex++) {
Cell cell = row.getCell(columnIndex);
if (cell != null) {
// 根据列名获取数据
String columnName = columnNames[columnIndex];
switch (cell.getCellType()) {
case STRING:
row_data.put(columnName, cell.getStringCellValue());
break;
case NUMERIC:
row_data.put(columnName, String.valueOf(cell.getNumericCellValue()));
break;
case BOOLEAN:
row_data.put(columnName, String.valueOf(cell.getBooleanCellValue()));
break;
default:
System.out.println(columnName + ": ");
}
}
}
}
sheet_data.add(row_data);
}
data.put(sheet.getSheetName(), sheet_data);
}
} catch (IOException | EncryptedDocumentException ex) {
ex.printStackTrace();
}
}
@Test
public void isTriangle() {
List<Map<String, String>> test_data = data.get(Thread.currentThread().getStackTrace()[1].getMethodName());
if (test_data != null)
for (Map<String, String> row_data : test_data) {
Triangle triangle = new Triangle(Double.parseDouble(row_data.get("a")), Double.parseDouble(row_data.get("b")), Double.parseDouble(row_data.get("c")));
Assert.assertEquals(triangle.isTriangle(), Boolean.parseBoolean(row_data.get("result")));
}
}
@Test
public void isIsoscelesTriangle() {
List<Map<String, String>> test_data = data.get(Thread.currentThread().getStackTrace()[1].getMethodName());
if (test_data != null)
for (Map<String, String> row_data : test_data) {
Triangle triangle = new Triangle(Double.parseDouble(row_data.get("a")), Double.parseDouble(row_data.get("b")), Double.parseDouble(row_data.get("c")));
Assert.assertEquals(triangle.isIsoscelesTriangle(), Boolean.parseBoolean(row_data.get("result")));
}
}
@Test
public void isEquilateralTriangle() {
List<Map<String, String>> test_data = data.get(Thread.currentThread().getStackTrace()[1].getMethodName());
if (test_data != null)
for (Map<String, String> row_data : test_data) {
Triangle triangle = new Triangle(Double.parseDouble(row_data.get("a")), Double.parseDouble(row_data.get("b")), Double.parseDouble(row_data.get("c")));
Assert.assertEquals(triangle.isEquilateralTriangle(), Boolean.parseBoolean(row_data.get("result")));
}
}
}
对于Excel数据
下载链接: [https://pan.baidu.com/s/1sTam_E_L4J3_7AljgRR5mA?pwd=c0gw]
测试结果