Skip to content

Junit5结合数据驱动 excel

JUnit5结合数据驱动-excel

excel 解析对比

解析方式 说明
JXL 开源的 Java Excel API 项目
2011 后未更新
JExcel 不是 JXL
2019 后未更新
Apache POI 官网
支持 xls、xlsx
社区强大,更新快,至今还在更新

pom 导入相关依赖

<properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <java.version>11</java.version>
    <!-- 使用 Java 11 语言特性 ( -source 11 ) 并且还希望编译后的类与 JVM 11 ( -target 11 )兼容,您可以添加以下两个属性,它们是默认属性插件参数的名称-->
    <maven.compiler.target>11</maven.compiler.target>
    <maven.compiler.source>11</maven.compiler.source>
    <!-- 对应junit Jupiter的版本号;放在这里就不需要在每个依赖里面写版本号,导致对应版本号会冲突-->
    <junit.jupiter.version>5.8.2</junit.jupiter.version>

    <maven.compiler.version>3.8.1</maven.compiler.version>
    <maven.surefire.version>3.0.0-M5</maven.surefire.version>
    <!-- plugins -->
    <maven-surefire-plugin.version>3.0.0-M5</maven-surefire-plugin.version>
    <poi.version>5.2.2</poi.version>
</properties>

<!--    物料清单 (BOM)-->
<dependencyManagement>
    <dependencies>
        <!--当使用 Gradle 或 Maven 引用多个 JUnit 工件时,此物料清单 POM 可用于简化依赖项管理。不再需要在添加依赖时设置版本-->
        <dependency>
            <groupId>org.junit</groupId>
            <artifactId>junit-bom</artifactId>
            <version>${junit.jupiter.version}</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>

    </dependencies>
</dependencyManagement>



<dependencies>
    <dependency>
        <groupId>org.junit.jupiter</groupId>
        <artifactId>junit-jupiter</artifactId>
        <!--            对应添加的依赖的作用范围-->
        <scope>test</scope>
    </dependency>

    <dependency>
        <groupId>org.junit.platform</groupId>
        <artifactId>junit-platform-suite</artifactId>
        <scope>test</scope>
    </dependency>

    <dependency>
        <groupId>org.junit.vintage</groupId>
        <artifactId>junit-vintage-engine</artifactId>
        <version>${junit.jupiter.version}</version>
    </dependency>


    <!-- https://mvnrepository.com/artifact/org.apache.poi/poi -->
    <dependency>
        <groupId>org.apache.poi</groupId>
        <artifactId>poi</artifactId>
        <version>${poi.version}</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/org.apache.poi/poi-ooxml -->
    <dependency>
        <groupId>org.apache.poi</groupId>
        <artifactId>poi-ooxml</artifactId>
        <version>${poi.version}</version>
    </dependency>

</dependencies>


<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-surefire-plugin</artifactId>
            <version>${maven-surefire-plugin.version}</version>

            <dependencies>
                <dependency>
                    <groupId>org.junit.jupiter</groupId>
                    <artifactId>junit-jupiter-engine</artifactId>
                    <version>${junit.jupiter.version}</version>
                </dependency>
                <dependency>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                    <version>${junit.jupiter.version}</version>
                </dependency>
            </dependencies>
        </plugin>
    </plugins>
</build>

poi 解析步骤

  • 1、获取文件名后缀
  • 2、查看文件是否存在
  • 3、获取工作薄对象Workbook
    • 如果是xls结尾用HSSF
    • 如果是xlsx结尾用XSSF
  • 4、读取第一个sheet
  • 5、获取行
  • 6、读取每一行的单元格内容
  • 7、最后关闭流

1、获取文件名后缀

我们需要先判断一下这个文件是否时 excel 文件,excel 文件的后缀有两种形式,.xls.xlsx

String pathname = "src/test/resources/orderLine.xlsx";
//substring截取左闭右开,从最后一个.右侧的位置到pathname末尾。
String excelType = pathname.substring(pathname.lastIndexOf(".") + 1, pathname.length());
assertThat("当前文件不是excel文件",excelType,anyOf(endsWithIgnoringCase("xlsx"),endsWithIgnoringCase("xls")));

2、查看文件是否存在

除了检查文件是否是 excel 文件,还需要检查这个文件是否存在,不存在的文件没有必要继续向下执行。

    //2.查看当前文件是否存在
    File file=new File(pathname);
    assertTrue(file.exists(),"文件不存在");

3、获取工作薄对象 Workbook

  • 使用输入流的形式打开文件获取工作薄对象
  • 直接使用 file 打开文件获取工作薄对象
    //3.获取workbook

    FileInputStream stream = new FileInputStream(file);
    Workbook workbook =null;
    //针对不同后缀的文件,获取方式也不同,所以需要做一个if判断
    //equalsIgnoreCase表示忽略大小判断是否相等
    if(excelType.equalsIgnoreCase("xls"))
    {
        //如果文件是xls的后缀,应该以HSSF声明
        workbook = new HSSFWorkbook(stream);
    }
    else if(excelType.equalsIgnoreCase("xlsx")){
        workbook = new XSSFWorkbook(stream);
    }

4、获取 sheet

  • 想要获取哪个就读取哪个 sheet
  • 获取当前工作薄有几个 sheet 标签页
//4.获取sheet
            //对应sheet页从0开始,int类型
            Sheet sheet=workbook.getSheetAt(0);
            //获取当前工作簿中一共有几个sheet
            int numberOfSheets= workbook.getNumberOfSheets();

获取行数
  • 获取 sheet 中有多少行
  • 一个 sheet 里面有多个 row
for(Row row:sheet ){
                ////为每一行创建一个数组存放内容,data中每个元素都为一个数组
                data.put(i,new ArrayList<>());
}

获取每一个单元格数据

在获取行的循环中嵌套一个循环来获取单元格数据

  • 一行「row」有多个单元格「Cell」

    //map<行号,list是行内容>
    Map<Integer, List<Object>> data = new HashMap<>();
    int i = 0;
    for (Row row : sheet) {
      //{0=[]}
      data.put(i, new ArrayList<Object>());
    
      for(Cell cell:row){
          //[]
          //每一个单元格就是ArrayList里面一个元素
          List<Object> objectList = data.get(i);
          objectList.add(cell);
      }
      i++;
    }
    System.out.println("data:" + data);
    
  • 如果控制台出现报错信息如下图
  • 需要在 pom.xml 文件中添加 log4j-core 依赖(不添加无影响)
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-core</artifactId>
            <version>2.14.1</version>
        </dependency>
  • 读取数据完整代码
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.junit.jupiter.api.Test;

import java.io.File;
import java.io.FileInputStream;
import java.sql.SQLOutput;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.anyOf;
import static org.hamcrest.Matchers.endsWithIgnoringCase;
import static org.junit.jupiter.api.Assertions.assertTrue;

public class ExcelTest {
    @Test
    void excelBaseTest() {
        try {
            //1.获取文件名后缀
            String pathname = "src/test/resources/orderLine.xlsx";
            //substring截取左闭右开,从最后一个.右侧的位置到pathname末尾。
            String excelType = pathname.substring(pathname.lastIndexOf(".") + 1, pathname.length());
            assertThat("当前文件不是excel文件",excelType,anyOf(endsWithIgnoringCase("xlsx"),endsWithIgnoringCase("xls")));
            //2.查看当前文件是否存在
            File file=new File(pathname);
            assertTrue(file.exists(),"文件不存在");
            //3.获取workbook

            FileInputStream stream = new FileInputStream(file);
            Workbook workbook =null;
            //针对不同后缀的文件,获取方式也不同,所以需要做一个if判断
            //equalsIgnoreCase表示忽略大小判断是否相等
            if(excelType.equalsIgnoreCase("xls"))
            {
                //如果文件是xls的后缀,应该以HSSF声明
                workbook = new HSSFWorkbook(stream);
            }
            else if(excelType.equalsIgnoreCase("xlsx")){
                workbook = new XSSFWorkbook(stream);
            }
            //4.获取sheet
            //对应sheet页从0开始,int类型
            Sheet sheet=workbook.getSheetAt(0);
            //获取当前工作簿中一共有几个sheet
            int numberOfSheets= workbook.getNumberOfSheets();
            //5.获取行
            //一个sheet对应的Java数据结构
            //每一行都是一个对象
            //Map<Integer, List<Object>> 对应 Map<行号,行的内容 >
            Map<Integer, List<Object>> data= new HashMap<>();
            //当前sheet中一共有多少行
            int numberOfRows = sheet.getPhysicalNumberOfRows();
            int i=0;//表示行号
            for(Row row:sheet ){
                //为每一行创建一个数组存放内容
                data.put(i,new ArrayList<>());
                //6、获取每一行的单元格的内容
                int physicalNumberOfCells = row.getPhysicalNumberOfCells();
                for (Cell c:row){
                    //通过将索引为`i`的元素赋值给`objects`,可以在后续的代码中使用`objects`来访问和操作该元素的内容。
                    //修改`objects`对象中的值时,会对`data`列表中的数据产生影响。这是因为`objects`实际上是指向`data.get(i)`所返回的列表的引用。
                    List<Object> objects = data.get(i);
                    objects.add(c);//将数据存入data中


                }
                i++;
//                System.out.println("physicalNumberOfCells-----"+physicalNumberOfCells);

            }
            System.out.println(data);
            //7、关闭流
            workbook.close();
        }catch (Exception e){
            throw new RuntimeException(e);
        }
    }
}
  • 效果如下
数据解析类型

目前我们可以正常读取数据了,但是可以看到日期的格式不规范,如果需要完善,可以添加以下代码

  • excel 可以设置列的数据类型
    switch (cell.getCellType()) {
      //单元格类型枚举值为STRING时,将使用Cell接口的getRichStringCellValue()方法读取内容:
      //文本格式的内容读取
      case STRING:
          cell.getRichStringCellValue().getString();
          break;
      // 数字、日期
      case NUMERIC:
          if (DateUtil.isCellDateFormatted(cell)) {
              //日期型以年-月-日格式存储
              SimpleDateFormat fmt = new SimpleDateFormat("yyyy-MM-dd");
              fmt.format(cell.getDateCellValue());
          } else {
              cell.getNumericCellValue();
          }
          break;
      case BOOLEAN:
          cell.getBooleanCellValue();
          break;
      case FORMULA:
          cell.getCellFormula();
          break;
      default: data.get(Integer.valueOf(i)).add(" ");
    }