Spock:从CSV文件读取测试数据 [英] Spock: Reading Test Data from CSV File

查看:407
本文介绍了Spock:从CSV文件读取测试数据的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想写一个优雅的Spock规范,它将从CSV文件读取一个非常大的测试数据,而无需将所有数据加载到内存中。

I'm trying to write an elegant Spock specification that will read a very large test data from CSV file without loading all the data into the memory. I'm looking for your feedback on how you might do it better than what I currently have here.

让我们假设我的简化CSV文件看起来像下面这样: -

Let's assume my simplified CSV file looks like the below:-

1,2
3,4
5,6

断言是column 1+ 1 ==column 2

我使用OpenCSV做我的CSV解析,因为实际的CSV文件包含特殊字符,如双引号和逗号的字符串,以及通过用逗号分隔字符串的基本解析不工作。

I'm using OpenCSV to do my CSV parsing simply because the actual CSV file contains strings with special characters like double quotes and commas, and rudimentary parsing through splitting the string by comma and such will not work.

<dependency>
    <groupId>net.sf.opencsv</groupId>
    <artifactId>opencsv</artifactId>
    <version>2.3</version>
</dependency>

尝试1

我的第一个尝试是循环遍历CSV并对每一行执行断言。虽然这种方法工作,我不能使用 @Unroll 将每个断言隔离成独立的独立测试。

My first attempt is to loop through the CSV and perform assertion on every row. While this approach works, I can't use @Unroll to isolate every assertion into separate independent tests.

def "read from csv"() {
    expect:
    def reader = new CSVReader(...)
    def fields

    while ((fields = reader.readNext()) != null) {
        def firstNum = Integer.valueOf(fields[0])
        def secondNum = Integer.valueOf(fields[1])

        firstNum + 1 == secondNum
    }
}

尝试2

此尝试允许我使用 @Unroll

@Unroll
def "read from csv"() {
    expect:
    Integer.valueOf(firstNum as String) + 1 == Integer.valueOf(secondNum as String)

    where:
    [firstNum, secondNum] << new CSVReader(...).readAll()
}

尝试3

阅读 http://spock-framework.readthedocs.org/en/latest/data_driven_testing.html#data-pipes ,我可以创建一个实现 Iterable ...和Spock只会指示数据提供者只在需要时查询下一个值,这正是我想要的。

After reading http://spock-framework.readthedocs.org/en/latest/data_driven_testing.html#data-pipes , I can just create an object that implements Iterable... and Spock will only instruct the data provider to query the next value only when it is needed, which is exactly what I want.

@Unroll
def "read from csv"() {
    given:
    CSVParser csvParser = new CSVParser()

    expect:
    def fields = csvParser.parseLine(line as String)
    def firstNum = Integer.valueOf(fields[0])
    def secondNum = Integer.valueOf(fields[1])

    firstNum + 1 == secondNum

    where:
    line << new Iterable() {
        @Override
        Iterator iterator() {
            return new Scanner(...)
        }
    }
}

这个尝试并不太糟糕,但看起来很奇怪,我必须在<$

This attempt isn't too bad, but it looks weird that I have to do some CSV parsing in the expect block that clutters the actual intent here, which is to perform the assertion.

尝试4

我最后的尝试创建了一个迭代器包装器,它将字段作为单独的变量返回,但是代码相当丑陋,除非我将Iterable类提取到单独的API。

My final attempt pretty much creates an iterator wrapper that will return the fields as separate variables, but the code is rather ugly to read unless I extract the Iterable class into a separate API.

@Unroll
def "read from csv"() {
    expect:
    Integer.valueOf(firstNum as String) + 1 == Integer.valueOf(secondNum as String)

    where:
    [firstNum, secondNum] << new Iterable() {
        @Override
        Iterator iterator() {
            new Iterator() {
                def reader = new CSVReader(...)

                def fields

                @Override
                boolean hasNext() {
                    fields = reader.readNext()
                    return fields != null
                }

                @Override
                Object next() {
                    return fields
                }

                @Override
                void remove() {
                    throw new UnsupportedOperationException()
                }
            }
        }
    }
}

问题

我的问题是...您会如何解决这个问题?有更好的方法(或更好的CSV库)?我知道Apache Commons CSV可能是唯一的解析器,我知道,实现 Iterable ,但它一直是 SNAPSHOT 很长时间。

My question is... how would you approach this problem? Is there a better way (or a better CSV library)? I know Apache Commons CSV is probably the only parser I'm aware of that implements Iterable, but it has been a SNAPSHOT for a long time.

非常感谢。

推荐答案

实现 Iterable< Iterable< String>> (或 Iterable CSVFile Iterable< Integer>> )。然后使用其中:[firstNum,secondNum]<新CSVFile(路径/到/文件)

Write a utility class CSVFile that implements Iterable<Iterable<String>> (or Iterable<Iterable<Integer>>). Then use where: [firstNum, secondNum] << new CSVFile("path/to/file").

这篇关于Spock:从CSV文件读取测试数据的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆