使用 JUnit 5 从 CSV 文件读取测试数据的最佳方法是什么?
What is best way of reading test data from CSV file with JUnit 5?
使用 JUnit 5 从 CSV 文件读取测试数据的best/suggested 方法是什么?
假设一行是一个测试用例,一列是一个参数,列数是固定的,不同的列可以有不同的(基本)类型:String、int、double。
例如:
public class Test{
@Test
// ready to use annotation that may load parameters from each line
public void shouldCalculateDiscount(String column1, long column2, double column3) {
assertEquals(5, column1.length());
assertEquals(column3, column2, 0.0001);
}
}
CSV 文件示例:
column1,column2,column3
a,0,0.0
abcde,1,1.01
a-b-c,999,999.0
使用注释的方法是完美的,可能类似于 JUnit 的 @ParameterizedTest。
Apache commons 有一个很好的 CSV 库供您使用。
http://commons.apache.org/proper/commons-csv/user-guide.html
CSV 代表逗号分隔值,因此本质上您可以拆分,因为您知道使用的分隔符。如果您尝试将测试数据用于多个测试,您可以尝试:
List<String[]> columnValues = new ArrayList<String[]>();
@Before
public void init(){
try {
Scanner scanner = new Scanner(new File("myFile.csv"));
while(scanner.hasNextLine()) {
String[] values = scanner.nextLine().split(",");
columnValues.add(values);
}
}catch(Exception e) {
//whatever
}
}
那么无论你使用什么测试方法,你都可以简单地分解这些值
@Test
public void myTest(){
//set x to 1 to avoid columns
for(int x = 1; x < columnValues.size(); x++) {
String col1 = columnValues.get(x)[0];
int col2 = Integer.parseInteger(columnValues.get(x)[1]);
double col3 = Double.parseDouble(columnValues.get(x)[2]);
double col4 = Double.parseDouble(columnValues.get(x)[3]);
//test values here
}
}
或者,如果您想要测试特定行,也可以使用特定索引,或者如果您愿意,甚至可以随机化它而不是测试所有行。正如您所提到的,您也可以将此概念用作测试参数。
令人惊讶的是,我发现了两种有据可查的方法,可以真正回答我的问题。
第一个 来自 Tomek Kaczanowski 的书 Practical Unit Testing with JUnit and Mockito。
他建议使用以下内容:
@RunWith(JUnitParamsRunner.class)
public class ReadCSVJunitParamsTest {
@Test
@FileParameters(value = "classpath:financial.csv", mapper = CsvWithHeaderMapper.class)
public void testLetterCount(String value, long letterCount) {
assertEquals(letterCount, LetterCounter.countLetters(value));
}
}
它使用 JUnitParams 库。它甚至可以测试参数值的 n 倍笛卡尔积“有效地测试每个可能的组合。”- 参见 @CombinedParameters
注释。
第二种方法使用@CsvSource和@ParameterizedTest的组合,直接来自.. JUnit 5.
public class ReadCSVJUnitParametrized {
@ParameterizedTest
@CsvFileSource(resources = "/financial.csv", numLinesToSkip = 1)
public void testLetterCountParametrized(String value, long letterCount) {
assertEquals(letterCount, LetterCounter.countLetters(value));
}
}
我用来测试的.csv文件:
value,letterCount
,0
a,1
..aa,2
.!@#$%^&*(,0
0123456789,0
abcdefghij0,10
LetterCounter class:
public class LetterCounter {
public static long countLetters(String value) {
if (value == null) {
return 0;
}
return value.chars().filter(Character::isLetter).count();
}
}
使用 JUnit 5 从 CSV 文件读取测试数据的best/suggested 方法是什么?
假设一行是一个测试用例,一列是一个参数,列数是固定的,不同的列可以有不同的(基本)类型:String、int、double。
例如:
public class Test{
@Test
// ready to use annotation that may load parameters from each line
public void shouldCalculateDiscount(String column1, long column2, double column3) {
assertEquals(5, column1.length());
assertEquals(column3, column2, 0.0001);
}
}
CSV 文件示例:
column1,column2,column3
a,0,0.0
abcde,1,1.01
a-b-c,999,999.0
使用注释的方法是完美的,可能类似于 JUnit 的 @ParameterizedTest。
Apache commons 有一个很好的 CSV 库供您使用。 http://commons.apache.org/proper/commons-csv/user-guide.html
CSV 代表逗号分隔值,因此本质上您可以拆分,因为您知道使用的分隔符。如果您尝试将测试数据用于多个测试,您可以尝试:
List<String[]> columnValues = new ArrayList<String[]>();
@Before
public void init(){
try {
Scanner scanner = new Scanner(new File("myFile.csv"));
while(scanner.hasNextLine()) {
String[] values = scanner.nextLine().split(",");
columnValues.add(values);
}
}catch(Exception e) {
//whatever
}
}
那么无论你使用什么测试方法,你都可以简单地分解这些值
@Test
public void myTest(){
//set x to 1 to avoid columns
for(int x = 1; x < columnValues.size(); x++) {
String col1 = columnValues.get(x)[0];
int col2 = Integer.parseInteger(columnValues.get(x)[1]);
double col3 = Double.parseDouble(columnValues.get(x)[2]);
double col4 = Double.parseDouble(columnValues.get(x)[3]);
//test values here
}
}
或者,如果您想要测试特定行,也可以使用特定索引,或者如果您愿意,甚至可以随机化它而不是测试所有行。正如您所提到的,您也可以将此概念用作测试参数。
令人惊讶的是,我发现了两种有据可查的方法,可以真正回答我的问题。
第一个 来自 Tomek Kaczanowski 的书 Practical Unit Testing with JUnit and Mockito。 他建议使用以下内容:
@RunWith(JUnitParamsRunner.class)
public class ReadCSVJunitParamsTest {
@Test
@FileParameters(value = "classpath:financial.csv", mapper = CsvWithHeaderMapper.class)
public void testLetterCount(String value, long letterCount) {
assertEquals(letterCount, LetterCounter.countLetters(value));
}
}
它使用 JUnitParams 库。它甚至可以测试参数值的 n 倍笛卡尔积“有效地测试每个可能的组合。”- 参见 @CombinedParameters
注释。
第二种方法使用@CsvSource和@ParameterizedTest的组合,直接来自.. JUnit 5.
public class ReadCSVJUnitParametrized {
@ParameterizedTest
@CsvFileSource(resources = "/financial.csv", numLinesToSkip = 1)
public void testLetterCountParametrized(String value, long letterCount) {
assertEquals(letterCount, LetterCounter.countLetters(value));
}
}
我用来测试的.csv文件:
value,letterCount
,0
a,1
..aa,2
.!@#$%^&*(,0
0123456789,0
abcdefghij0,10
LetterCounter class:
public class LetterCounter {
public static long countLetters(String value) {
if (value == null) {
return 0;
}
return value.chars().filter(Character::isLetter).count();
}
}