Junit5-数据驱动
Java5+maven3.8+idea2022.2
junit5可以通过文件加载数据,如下4种文件加载数据
- yaml
- excel
- csv
- json
1. 解析yaml文件数据
首先要加载依赖到pom.xml,下面解析yaml需要这些依赖
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.13.1</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-yaml</artifactId>
<version>2.13.1</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
<version>2.13.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.12.1</version>
</dependency>
在resources下创建 yaml文件,里面以key value 的形式 存放数据,如下所示:
#这是个list 一个-代表一个对象
- item: No. 9 Sprockets
quantity: 12
price: 1.23
date: 2019-04-17
- item: No. Widget (10mm)
quantity: 10
price: 3.45
date: 2022-01-16
Yaml文件中数据格式是Key Value格式,因此可以解析到Map中以key value的形式存储,也可以解析到一个与yaml数据相似的结构体中
首先看到上面的yaml文件里包含2组数据,如果解析成对象的话就是2个对象,解析成Map的话,就是2个Map,看下面代码,介绍这2种解析方式
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
import com.zqh.pojo.PlanInfo;
import org.junit.jupiter.api.Test;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
public class YamlTest {
String url = "src/test/resources/orderlist.yaml";
@Test
//使用Map key value的形式接收数据
//yaml中是2组数据,因此这里定义List来存放Map
void listTest() throws IOException {
ObjectMapper objectMapper = new ObjectMapper(new YAMLFactory());
//解析yaml文件内容
TypeReference<List<HashMap<String, String>>> typeReference =
new TypeReference<List<HashMap<String, String>>>() {
};
List<HashMap<String,String>> list= objectMapper.readValue(new File(url),typeReference); //读取yaml文件 并解析到 typeReference
System.out.println(list);
}
@Test
//使用实体类对象的形式接收yaml数据,
//yaml中的key名称应该与实体类的参数名一一对应
//成员变量与yaml里的key不一致时,实体类使用注解@JsonProperty("item")来做映射
void PlanTest() throws IOException {
ObjectMapper objectMapper = new ObjectMapper(new YAMLFactory());
//objectMapper.findAndRegisterModules();//为了正常处理 日期类型
//将yaml文件的内容 转换为实体类
TypeReference<List<PlanInfo>> typeReference =
new TypeReference<List<PlanInfo>>() {
};
List<PlanInfo> infos = objectMapper.readValue(new File(url), typeReference);
System.out.println(infos);
}
}
这个实体类必须要有无参构造方法,并如果yaml里的key与实体类的参数名不一致的时候需要使用注解 @JsonProperty(“item”)来显示声明 yaml的key对应哪一个参数,如果两者的名称一致,可以不适用此注解,将会自动对应解析
import java.math.BigDecimal;
import java.time.LocalDate;
/**
* 使用注解 JsonProperty,来匹配实体类字段
*/
public class PlanInfo {
@JsonProperty("item")
private String item;
@JsonProperty("quantity")
private int quantity;
@JsonProperty("price")
private BigDecimal price;
@JsonProperty("date")
private LocalDate date;
public String getItem() {
return item;
}
public void setItem(String item) {
this.item = item;
}
public int getQuantity() {
return quantity;
}
public void setQuantity(int quantity) {
this.quantity = quantity;
}
public BigDecimal getPrice() {
return price;
}
public void setPrice(BigDecimal price) {
this.price = price;
}
public LocalDate getDate() {
return date;
}
public void setDate(LocalDate date) {
this.date = date;
}
@Override
public String toString() {
return super.toString();
}
public PlanInfo(){
}
public PlanInfo(String item,int quantity,LocalDate date,BigDecimal price){
this.item = item;
this.date = date;
this.price = price;
this.quantity = quantity;
}
}
2. 加载excel
这里解析excel使用的是 apache poi 依赖
<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>
poi解析步骤:
获取工作簿的对象Workbook 区分文件类型 如果是xls后缀要使用HSSF 如果是xlsx结尾要用XSSF
1获取文件名后缀->2验证文件是否存在->3获取工作簿的对象Workbook-> 4读取第一个sheet->获取行->5读取每一行的单元格内容->6最后关闭流
excel里的内容如下:
用代码实现上面步骤
public class ExcelParamTest {
String filePath = "src/test/resources/param.xlsx";
@Test
//读取excel表格中的数据
public void ReadExcel() throws IOException {
//步骤一 获取文件后缀名,截取.后面的到文件最后这一段字符串,判断文件后缀
String suffix = filePath.substring(filePath.lastIndexOf(".") - 1, filePath.length());
assertThat("改文件不是excel", suffix, is(anyOf(endsWithIgnoringCase("xlsx"), endsWithIgnoringCase("xls"))));
//步骤二 判断文件是否存在
File file = new File(filePath);
assertTrue(file.exists(), "文件不存在");
//步骤三 获取工作簿对象
Workbook workbook = null;
FileInputStream io = new FileInputStream(file);
if (suffix == "xlsx") {
workbook = new XSSFWorkbook();
} else {
workbook = new HSSFWorkbook();
}
//步骤四 读取sheet页
Sheet sheet = new workbook.getSheetAt(0);//获取第一个sheet对象
int numOfSheets = workbook.getNumberOfSheets();//当前有几个sheet页
int numOfRows = sheet.getPhysicalNumberOfRows();//这个sheet有多少行
//步骤五 读取每一个单元格
//将数据放在 map里 key是行号,value是list
HashMap<Integer, List<Object>> map = new HashMap<>();
int i = 0;
for (Row row : sheet) {
map.put(i, new ArrayList<>());
int numOfCells = row.getPhysicalNumberOfCells();
for (Cell cell : row) {
List<Object> objects = map.get(i);
//objects.add(cell);
CellType type = cell.getCellType();
Object cellValue = getCellValue(cell);
objects.add(cellValue);
}
i++;
}
workbook.cloneSheet(0);
workbook.close();
}
public Object getCellValue(Cell cell) {
CellType cellType = cell.getCellType();
switch (cellType) {
case STRING: //字符串
String str = cell.getRichStringCellValue().toString();
return str;
case NUMERIC://数字 日期
if (判断是日期) {//判断是日期
SimpleDateFormat fmt = new SimpleDateFormat("yyyy-MM-dd");
return fmt.format(cell.getDateCellValue());
} else {
return cell.getNumericCellValue();
}
case BOOLEAN:
return cell.getBooleanCellValue();
case FORMULA:
return cell.getCellFormula();
default:
return null;
}
}
}
3. 加载csv文件数据
需要先加载csv使用的依赖到pom.xml,如下:
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-csv</artifactId>
<version>2.13.1</version>
</dependency>
声明一个实体类 ,包含的字段与csv的header一致
import java.math.BigDecimal;
import java.time.LocalDate;
public class ParamInfo {
private String item;
private int quantity;
private BigDecimal price;
private LocalDate date;
public String getItem() {
return item;
}
public void setItem(String item) {
this.item = item;
}
public int getQuantity() {
return quantity;
}
public void setQuantity(int quantity) {
this.quantity = quantity;
}
public BigDecimal getPrice() {
return price;
}
public void setPrice(BigDecimal price) {
this.price = price;
}
public LocalDate getDate() {
return date;
}
public void setDate(LocalDate date) {
this.date = date;
}
public ParamInfo(String item, int quantity, BigDecimal price, LocalDate date) {
this.item = item;
this.quantity = quantity;
this.price = price;
this.date = date;
}
public ParamInfo() {
}
@Override
public String toString() {
return "CSVParamTest{" +
"item='" + item + '\'' +
", quantity=" + quantity +
", price=" + price +
", date=" + date +
'}';
}
}
csv的第一行一般用来放参数名,从第二行开始放参数值
将csv的header映射给实体类的字段可以看出csv有2行数据,因此对应2个对象,使用MappingIterator来接收多个对象
下面的代码是,当csv的header与实体类的参数一一对应的情况
public class CSVParamTest {
String url = "src/test/resources/params.csv";
@Test
public void readCsv() throws IOException {
CsvMapper csvMapper = new CsvMapper();
//CsvSchema 读取csv的模式 这里是使用header读取
CsvSchema orderLineSchema = CsvSchema.emptySchema().withHeader();//带着header读取
//csvMapper.findAndRegisterModules();//这个用来正确处理日期类型
//用一个迭代器接收数据,用header映射实体类的参数
MappingIterator<ParamInfo> params = csvMapper.readerFor(ParamInfo.class)
.with(orderLineSchema).readValues(new File(url));
System.out.println(params);
}
}
有时候csv字段与实体类的字段并不一致,需要手动映射
在实体类上的参数上增加注解@JsonProperty(“csv中字段名称”)
另外可以过滤掉首行也就是header头,再自己定义header,如下看代码:
@Test
public void readCsv2() throws IOException {
CsvMapper mapper = new CsvMapper();
//setSkipFirstDataRow(true) 不解析第一行 csv header 手动给按照顺序增加表头
CsvSchema schema = CsvSchema.builder().setSkipFirstDataRow(true)
.addColumn("item")
.addColumn("quantity")
.addColumn("price")
.addColumn("date")
.build();
MappingIterator<Object> mapping = mapper.readerForMapOf(String.class)
.with(schema)
.readValues(new File(url));
System.out.println(mapping.readAll());
}
4. 解析json
json文件的数据读取与yaml相似
所需要的依赖也与yaml一样,这里不重复写了,直接上代码
定义json文件1,json文件内容如下,是一个数组,数组里有2条数据
[
{
"item":"No.9 sss",
"quantity":12,
"price": 4,
"date": "2022-08-17"
},
{
"item":"No.10 lal",
"quantity":13,
"price": 7,
"date": "2022-08-17"
}
]
定义json文件2,如下所示,只有一条数据,但是其中内部有一个数组
{
"orderNo": "A001",
"date": "2022-08-17",
"customerName": "Customer,joe",
"orderLines": [
{
"item": "No.10",
"quantity": 12,
"price": 2.3
},
{
"item": "No.11",
"quantity": 17,
"price": 2.5
}
]
}
下面介绍,将上面的json解析成k-v形式的map以及解析成实体类,因此定义json对应的实体类
实体类1对应json1,json的key与实体类的参数名一一对应
import com.fasterxml.jackson.annotation.JsonProperty;
import java.math.BigDecimal;
import java.time.LocalDate;
public class ParamInfo {
@JsonProperty("item")
private String item;
@JsonProperty("quantity")
private int quantity;
@JsonProperty("price")
private BigDecimal price;
@JsonProperty("date")
private LocalDate date;
public ParamInfo(String item, int quantity, BigDecimal price, LocalDate date) {
this.item = item;
this.quantity = quantity;
this.price = price;
this.date = date;
}
public ParamInfo() {
}
@Override
public String toString() {
return "CSVParamTest{" +
"item='" + item + '\'' +
", quantity=" + quantity +
", price=" + price +
", date=" + date +
'}';
}
public String getItem() {
return item;
}
public void setItem(String item) {
this.item = item;
}
public int getQuantity() {
return quantity;
}
public void setQuantity(int quantity) {
this.quantity = quantity;
}
public BigDecimal getPrice() {
return price;
}
public void setPrice(BigDecimal price) {
this.price = price;
}
public LocalDate getDate() {
return date;
}
public void setDate(LocalDate date) {
this.date = date;
}
}
实体类2,对应json2,他们的名称也是一一对应的,因此不写注解了
import java.time.LocalDate;
import java.util.List;
public class ParamInfo2 {
private String orderNo;
private LocalDate date;
private String customerName;
List<ParamInfo> orderLines;
public ParamInfo2() {
}
public ParamInfo2(String orderNo, LocalDate date, String customerName, List<ParamInfo> orderLines) {
this.orderNo = orderNo;
this.date = date;
this.customerName = customerName;
this.orderLines = orderLines;
}
@Override
public String toString() {
return "ParamInfo2{" +
"orderNo='" + orderNo + '\'' +
", date=" + date +
", customerName='" + customerName + '\'' +
", orderLines=" + orderLines +
'}';
}
public String getOrderNo() {
return orderNo;
}
public void setOrderNo(String orderNo) {
this.orderNo = orderNo;
}
public LocalDate getDate() {
return date;
}
public void setDate(LocalDate date) {
this.date = date;
}
public String getCustomerName() {
return customerName;
}
public void setCustomerName(String customerName) {
this.customerName = customerName;
}
public List<ParamInfo> getOrderLines() {
return orderLines;
}
public void setOrderLines(List<ParamInfo> orderLines) {
this.orderLines = orderLines;
}
}
下面的代码介绍将2种json解析成map和结构体
import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.jupiter.api.Test;
import pojo.ParamInfo;
import pojo.ParamInfo2;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Parameter;
import java.util.HashMap;
import java.util.List;
public class JsonParamTest {
String url = "src/test/resources/params.json";
String url2 = "src/test/resources/params2.json";
@Test
//json1 解析到HashMap中,由于有2组数,因此放入List
public void JsonTest() throws IOException {
ObjectMapper objectMapper = new ObjectMapper(new JsonFactory());
objectMapper.findAndRegisterModules();//为了正常处理 日期类型
TypeReference<List<HashMap<String,Object>>> ref = new TypeReference<List<HashMap<String, Object>>>() {
};
List<HashMap<String,Object>> list = objectMapper.readValue(new File(url),ref);
System.out.println(list);
}
@Test
//json1 使用实体类解析,json中包含2个对象,使用List接收
public void JsonTest2() throws IOException {
ObjectMapper objectMapper = new ObjectMapper(new JsonFactory());
objectMapper.findAndRegisterModules();//为了正常处理 日期类型
TypeReference<List<ParamInfo>> ref = new TypeReference<List<ParamInfo>>() {};
List<ParamInfo> list = objectMapper.readValue(new File(url),ref);
System.out.println(list);
}
@Test
//json2解析 到map
//这次就一个对象,因此用Map接收,不用使用List
public void JsonTest3() throws IOException {
ObjectMapper objectMapper = new ObjectMapper(new JsonFactory());
//objectMapper.findAndRegisterModules();//为了正常处理 日期类型
TypeReference<HashMap<String,Object>> ref = new TypeReference<HashMap<String, Object>>() {
};
HashMap<String,Object> map = objectMapper.readValue(new File(url2),ref);
System.out.println(map);
}
@Test
//json2 解析成结构体,这里只有一条数据因此使用一个对象接收数据即可
public void JsonTest4() throws IOException {
ObjectMapper objectMapper = new ObjectMapper(new JsonFactory());
TypeReference<ParamInfo2> ref = new TypeReference<ParamInfo2>() {};
objectMapper.findAndRegisterModules();//为了正常处理 日期类型
ParamInfo2 info = objectMapper.readValue(new File(url2),ref);
System.out.println(info.toString());
}
}