上篇文章 走进Java接口测试之测试框架TestNG数据驱动(入门篇)阐述测试框架 TestNG 中的一些基本的概念和玩法,本文带着大家来解决一个实际的工程问题。
使用文本做数据驱动的时候出现 JVM Heap 区 OOM。
核实下 IDEA 的 JVM 参数设置,JVM 最大可用内存为 2G:
考虑到参数化文件大概有 20 万条记录,判断这是由于程序一次性读取大量的文本数据导致的。
这时候我们想到测试框架 TestNG 有为这种大量数据驱动场景提供解法,即:延迟数据提供者。
有的场景我们需要大量参数进行读取,比如参数数据源是 DB,而数据达到百万级,这样测试程序遍历所有数据时,可能就会导致内存溢出。那么我们怎样解决这个问题?当我们获取了一条数据,对它执行测试方法,然后就废弃这个数据对象,再测试下一个。这个原则是延迟初始化,这个思想就是当你真正需要一个对象时才创建它,而不是提前创建它。
为了实现这种延迟加载的方法,TestNG 允许我们从数据提供者返回一个 Iterator 对象,而不是一个二维对象数组。
Iterator 是 java.util 包中的一个接口,它的方法签名如下:
public interface Iterator<E> {
boolean hasNext(); E next(); default void remove();
}
它可以通过 next 调用下一组数据,这样就有机会在最后一刻实例化相应的对象,即刚好在需要在这些参数的测试方法被调用之前。这样的好处是不用把所有的测试数据都加载到内存中,而是需要的时候就读一条。
首先配置 maven 依赖包:
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <!--引入 testng 测试框架--> <dependency> <groupId>org.testng</groupId> <artifactId>testng</artifactId> <version>6.14.3</version> <scope>compile</scope> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> <exclusions> <exclusion> <groupId>org.junit.vintage</groupId> <artifactId>junit-vintage-engine</artifactId> </exclusion> </exclusions> </dependency> </dependencies>
然后实现 Iterator 接口,用于从文件中读取数据,返回给被测试类:
@Slf4jpublic class TxtIterator implements Iterator<Object[]> {
/** * 数据文件 */ File txtFile; BufferedReader bs; String currentLine;
public TxtIterator(File txtFile) throws IOException { super(); this.txtFile = txtFile; try { bs = new BufferedReader(new FileReader(txtFile)); } catch (FileNotFoundException e) { log.error("文件找不到"); e.printStackTrace(); } currentLine = bs.readLine(); }
@Override public boolean hasNext() { if (currentLine != null) { return true; } else { return false; } }
@Override public String[] next() { String returnLine = currentLine; try { currentLine = bs.readLine(); } catch (IOException e) { e.printStackTrace(); } return returnLine.split(","); }
@Override public void remove() { throw new UnsupportedOperationException("remove"); }}
@DataProvider
函数调用:
String filePath; // 文件名
@Parameters({"filePath"}) @BeforeClass() public void beforeClass(String filePath) { log.info("文件路径:[{}]",filePath); this.filePath = System.getProperty("user.dir") + "\\" + filePath;; }
@DataProvider(name = "iterator") public Iterator<Object[]> iteratorDataProvider() throws IOException { log.info("文件路径:[{}]",filePath); return new TxtIterator(new File(filePath)); }
@Test
测试运行函数:
@Test(dataProvider = "iterator" ,description = "测试延迟提供数据") public void testcase2(String username,String password) throws InterruptedException { log.info(" username = [{}] ,password = [{}]" ,username,password );
// 休眠2秒 Thread.sleep(2000); }
整体测试类代码:
@SpringBootTest@Slf4jpublic class DataProviderTest extends AbstractTestNGSpringContextTests {
String filePath; // 文件名
@Parameters({"filePath"}) @BeforeClass() public void beforeClass(String filePath) { log.info("文件路径:[{}]",filePath); this.filePath = System.getProperty("user.dir") + "\\" + filePath;; }
@DataProvider(name = "iterator") public Iterator<Object[]> iteratorDataProvider() throws IOException { log.info("文件路径:[{}]",filePath); return new TxtIterator(new File(filePath)); }
@Test(dataProvider = "iterator" ,description = "测试延迟提供数据") public void testcase2(String username,String password) throws InterruptedException { log.info(" username = [{}] ,password = [{}]" ,username,password );
// 休眠2秒 Thread.sleep(2000); }
}
testng.xml
:
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd"><suite name="Suite"> <parameter name="filePath" value="data.txt"/> <!--文件名--> <test name="DataProviderTest"> <classes> <class name="com.zuozewei.springboottextdatadrivendemo.TestCase.DataProviderTest" /> </classes> </test></suite>
数据文件 data.txt
:
Liming,12HanMeimei,13Lily,11Lucy,12
运行结果:
这样就实现了延迟提供的数据驱动。
示例代码:
https://github.com/7DGroup/Java-API-Test-Examples/tree/master/springboot-text-data-driven-demo