对于TDD,我该如何准备数据
在开始编写一个测试之前,准备数据是一个比较头疼的问题。对于一个测试,我至少有两种方法来准备数据:
1. 创建一个带数据的文件,在before的方法中加载它
2. 创建一个builder在代码中构建一个数据的文件流或内存对象
这两种方法都可以达到我的目的,那么我该用那种方法呢?首先,我需要知道两种方法的各自优势和缺点是什么?
1. 模版数据文件,这种方法准备数据快并且简单,我们可以从实际的系统中导出一个文件用于测试,数据量可以比较多。但缺点是测试代码必须知道这个文件的位置,测试的部署比较麻烦,而且文件格式的变化会导致测试失败。如果不同测试对数据内容需求不同,就要创建新的文件来适应测试变化。
2. 动态创建数据流/内存对象,这种方法相对比较灵活,可以随意的组织数据,数据的创建过程与测试代码能更好的保持同步,并且不会受数据文件的位置影响。缺点是如果要准备大数据量,非常费力,而且速度会很慢。
所以结论是当我们的测试需要数据量小并且格式灵活的时候,我们应当用动态数据流/内存对象,通常这也是单元测试的特点。如果我们的测试需要大量固定格式的数据,那么我们应该用模版数据文件,这种特点通常是集成测试或功能测试的特点。
理论只有联系实际才能产生效果。下面以创建一个CVS读写对象来说明这个理论。
假设我要写一个CvsOperator来读写CVS文件,目的是我能通过行号和列号来获取字段内容。这个时候,我在想我是从什么地方找一个现成的cvs文件呢?还是创建一个cvs builder的内存对象。按照TDD的做法,我们应该以尽可能小的步骤前进,而一个大而全的CVS文件对我来说太复杂了。所以我创建了一个简单的CvsFileBuilder对象
class CvsFileBuilder { private StringBuffer stringBuffer = new StringBuffer(); public ByteArrayInputStream getCvsFileStream() { ByteArrayInputStream cvsFileStream = new ByteArrayInputStream(stringBuffer.toString().getBytes()); return cvsFileStream; } public void buildHead(String line) { stringBuffer.append(line+"\r\n"); } }
非常的简单,就是读写流。接来了写一个测试,
@Test public void should_read_head_from_cvs_file() throws IOException { CvsFileBuilder simpleBuilder = new CvsFileBuilder(); simpleBuilder.buildHead("id,user_name,password"); CvsOperator cvsOperator = new CvsOperator(); cvsOperator.load(simpleBuilder.getCvsFileStream()); CvsOperator.CvsHead head = cvsOperator.getHead(); assertThat(head.getField(0), is("id")); assertThat(head.getField(1), is("user_name")); assertThat(head.getField(2), is("password")); }
因为这个时候的CvsOperator没有任何实现代码所以你会看到很多红的警告。这也是我们要去实现的方法。所以我就继续coding下去。
public class CvsOperator { private CvsHead head; public void load(ByteArrayInputStream cvsFileStream) throws IOException { BufferedReader br = new BufferedReader(new InputStreamReader(cvsFileStream)); head = new CvsHead(br.readLine()); } public CvsHead getHead() { return head; } class CvsHead { private final String[] headFields; public CvsHead(String line) { headFields = line.split(","); } public String getField(int index) { return (headFields.length > index) ? headFields[index] : null; } } }
非常快速的让测试通过,是TDD的一个原则。未完待续^_^