java单元测试与文件系统中的二进制文件交互的方法

时间:2012-05-08 08:33:17

标签: java unit-testing file-io mocking junit4

我对java编程很陌生,但我会尝试使用正确的术语,尽可能避免误解。

我找到了一些与我的问题非常相似的主题的答案,但或者我只是看不出他们如何真正适合我的问题,或者他们真的只是不适合。他们中的一些人使用模拟对象,但我不确定这是我的正确选择。

一般说明

我需要一个对象数组,从随机访问的二进制文件中加载信息。二进制文件的第一个字节是文件的标题,它定义了数据如何存储在文件中,基本上表示某些字段的长度有助于计算文件中所需数据的位置。

所以现在我想测试将被调用的方法,以便将 UnitListElement 对象指定的所需数据加载到 Unit 对象。为此,我只专注于单个读取二进制文件。

更详细的视图

我有一个名为 Unit 的java类,带有一些属性,比方说 a ,* b *和 c 。使用方法调用 getDataFromBinFile 加载此属性的值:

public class Unit{
    public double[] a;
    public double[] b;
    public double[] c;

getDataFromBinFile(UnitListElement element){
    <here loads the data from the binary file with random access>
}
}

从二进制文件加载数据的方法,打开二进制文件并访问二进制文件中的所需数据。要读取的所需数据在 UnitListElement 对象中指定:

public class UnitListElement{
    public String pathOfFile;
    public int beginToReadAt;  // info related to where the desired data begins
    public int finishReading;  // info related to where the desired data ends
} 

使用的属性 beginToReadAt finishReading 时间引用以及二进制文件的标头,用于计算从二进制文件中读取的第一个和最后一个字节位置。

所以我需要做的是一个测试,我调用方法 getDataFromBinFile(unitListEl)并测试返回的信息是否正确。

解决方案选项

第一个选项

在一些有类似问题的帖子中建议使用模拟对象。我试图找到关于模拟对象的文档,但我还没有找到任何简单的初学者指南。因此,虽然不太了解模拟对象,但我的印象是不适合这种情况,因为我想要测试的是读取二进制文件,而不仅仅是与其他对象的交互。

第二个选项

另一种选择是使用辅助方法f.i为测试内部的测试创建二进制文件。使用@BeforeClass,并使用此临时文件运行测试,然后使用@AfterClass方法将其删除。

问题

您认为考虑TDD方法的最佳做法是什么?模拟对象真的适合这种情况吗?如果他们这样做,是否有任何关于初学者的基本示例的文档?

或另一方面,文件的创建更适合测试阅读方法吗?

感谢

提前多多感谢。

4 个答案:

答案 0 :(得分:1)

模拟可以应用于您的案例,但事实上这并非严格必要。您所需要的只是将getDataFromBinFile中的实际数据处理逻辑与从文件中读取字节的代码分离。

您可以(至少)以两种方式实现这一目标:

  • 使用mocks:隐藏接口方法后面的文件读取代码,该方法接受UnitListElement并返回字节数组,然后在getDataFromBinFile中使用它。然后,您可以使用模拟阅读器在测试中模拟此接口,模拟阅读器只返回一些预定义的字节而无需访问任何文件(或者,您可以将文件读取逻辑移动到UnitListElement本身,因为现在它似乎是一个POD类。)
  • 没有模拟:更改getDataFromBinFile的签名以获取字节数组参数而不是UnitListElement。在您的真实生产代码中,您可以从UnitListElement描述的文件位置读取数据,然后将其传递给getDataFromBinFile。在单元测试中,您可以直接将任何二进制数据传递给它。 (请注意,在这种情况下,将方法重命名为getDataFromBytes。)
  • 是有意义的

对于模拟,到目前为止我一直在使用EasyMock。我发现its documentation相当容易理解,希望有所帮助。

答案 1 :(得分:0)

我对TDD没有多少经验。在测试对文件的读/写时,不需要使用模拟,最好的选择是测试运行的文件的测试版本。当您无法轻松为您的用例创建可测试对象时,即使您正在测试与服务器的交互时,可以使用模拟。

答案 2 :(得分:0)

我不喜欢创建测试二进制文件,因为正在读取的文件格式的任何更改都意味着更改测试文件(以及测试)。

由于您正在遵循TDD方法,因此您必须为&#34; UnitListElement&#34;编写测试。因此,对于情况来说,嘲弄似乎是一个更好的解决方案。你的目标是测试&#34; getDataFromBinFile&#34;方法而不是&#34; UnitListElement&#34;类方法(当前)因此你可以模拟&#34; UnitListElement&#34; class(或由它继承并传递给getDataFromBinFile方法的接口)。 Mocking&#34; UnitListElement&#34;意味着只要在&#34; getDataFromBinFile&#34;中访问它,就可以将预定义或任何特定的返回值返回给类中的任何方法调用。方法 。最后,您可以在&#34; getDataFromBinFile&#34;中使用模拟中返回的值。执行业务逻辑后,方法和断言方法的返回值。我没有使用太多的模拟框架,但是大多数时候我一直在使用EasyMock框架。首先,您可以获得EasyMock的基本示例here

答案 3 :(得分:0)

只需制作测试二进制文件。

此过程正在读取文件。所以没有理由担心文件系统。该文件将始终是确定性的(如果您在另一个故事的阅读中更改了文件)

如果您想在读完对象后对对象进行测试,我建议您在测试中创建它们(除非这很难做,如声音文件)

另外,我建议抽象流而不是文件,但我仍然会用测试文件测试它。顺便说一句:确保测试文件很小,毕竟这是一个测试。

有些人可能会争辩说“测试不应该打到文件系统”,但你认为从哪里加载.class文件?

另外,我会通过java classLoader获取流

this.getClass().getResourceAsStream("yourfile.name");
快乐的测试!

Llewellyn Falco

http://www.approvaltests.com