如何使用EasyMock测试写入/读取文件

时间:2013-01-06 09:44:16

标签: java unit-testing testing junit easymock

我是初学者,让自己掌握在手中。 我需要测试这个方法 - 写入/读取文件。你能得到建议吗?我能做得更好,只使用junit测试或更好的EasyMock?你还想建议做什么?

public class AbsFigure {

public void write(String fileName, List<FigureGeneral> figuresList) {
    try {
        PrintWriter out = new PrintWriter(
                new File(fileName).getAbsoluteFile());
        try {
            for (int i = 0; i < figuresList.size(); i++) {
                out.println(figuresList.get(i).toString());
            }
        } finally {
            out.close();
        }
    } catch (IOException e) {
        e.printStackTrace();
        System.out.println("Cannot write to file!");
    }
}

// read from file
private ArrayList<FigureGeneral> figureReader(String fileName) {
    String line = null;
    ArrayList<FigureGeneral> myListFigure = new ArrayList<FigureGeneral>();

    try {
        File myFile = new File(fileName);
        FileReader fileReader = new FileReader(myFile);
        BufferedReader bufferedReader = new BufferedReader(fileReader);

        while ((line = bufferedReader.readLine()) != null) {
            myListFigure.add(fromStringToFigureGeneral(line));
        }
        System.out.println(myListFigure);
        bufferedReader.close();

    } catch (FileNotFoundException e) {
        System.out.println("File which You loking for not found!");
    } catch (NumberFormatException e) {
        e.printStackTrace();
    } catch (IOException e) {
        System.out.println("Wrong input!");
    }

    return myListFigure;
}

// change from String to FigureGeneral(Triangle or Rectangle)
private FigureGeneral fromStringToFigureGeneral(String line) {
    String[] arrayLines = line.split(" ");
    FigureGeneral figures = null;

    if (arrayLines[0].equals("triangle")) {
        figures = new Triangle(Double.parseDouble(arrayLines[1]),
                Double.parseDouble(arrayLines[2]), "triangle");
    } else {
        figures = new Rectangle(Double.parseDouble(arrayLines[1]),
                Double.parseDouble(arrayLines[2]), "rectangle");
    }

    return figures;
}

public void launch(AbsFigure absFigure) {
    List<FigureGeneral> figuresList = absFigure.generateRandomFigures(5);

    AreaCompare areaCompare = new AreaCompare();
    Collections.sort(figuresList, areaCompare);

    absFigure.write("test.txt", figuresList);
    figureReader("test.txt");
}

public static void main(String[] args) {
    AbsFigure absFigure = new AbsFigure();
    absFigure.launch(absFigure);
}
}

我写了更多的代码,你可以更好地了解情况。我希望你可以推荐如何测试这个(也许你可以展示两种变体)。

4 个答案:

答案 0 :(得分:3)

通过使用内存I / O,您可以完全绕过磁盘I / O的使用。你不需要EasyMock,只需要不同的输入和输出流。您可以通过检查生成的输出流(write)和生成的FigureGeneral对象列表(读取)来断言您的方法与JUnit一起正常工作。

一步一步:

1)注入write方法将使用的输出流。

你可以添加另一个&#34;写&#34;您已经存在的&#34;写&#34;获取具有如下签名的输出流的方法:

public void write(OutputStream outputStream, List<FigureGeneral> figuresList);

您的原始write方法将通过调用以下方法来包装上述方法:

write(new FileOutputStream(new File(fileName).getAbsoluteFile()), figuresList);

2)使用InputStream对read方法重复上述技巧。

这会给你一个带有这样签名的读取方法:

private ArrayList<FigureGeneral> figureReader(InputStream inputStream);

3)现在编写使用ByteArrayInputStream和ByteArrayOutputStream的JUnit测试并调用上述方法。

您可以通过在ByteArrayOutputStream上调用toByteArray()并断言结果来检查write方法的结果。您可以通过在传递某个ByteArrayInputStream之后断言List中的值来检查read方法的结果。

这是一个(伪)方法,您可以添加到测试类中,断言不同性质的FigureGeneral对象列表可以写入输出流,从输入流中读回并相等。

public void assertCanBeWrittenAndReaback(List<FigureGeneral> inputFigure) {
  ByteArrayOutputStream outStream = new ByteArrayOutputStream();
  absFigure.write(outStream, inputFigures);
  List<FigureGeneral> outputFigure = absFigure.figureReader(new ByteArrayInputStream(outStream.toByteArray()));
  assertEqualsFigureGeneralLists(inputFigure, outputFigure);
}

4)这将为您提供相当不错的测试覆盖率。尽管如此,如果你想要达到100%的测试覆盖率,你仍然需要测试现在已成为包装器的orignal write和readFigure方法。

原始方法只是重定向到使用输入和输出流的同名语言。您可以通过覆盖(或实现,如果您将这些方法置于接口后面)两个重定向方法并声明它们接收正确的FileInputStream和FileOutputStream对象,使用EasyMock检查其重定向。虽然FileOutputStream构造函数需要现有文件,但您需要一些临时文件。但是,我没有看到在测试用例中使用临时文件的任何重大问题。

答案 1 :(得分:1)

经验法则是:只有你拥有的东西。模拟文件读者和作者并不是一个好主意。在这种情况下,集成测试更好 - 您希望测试是否正确地将代码与Java IO API集成在一起。所以只需将数据写入一些临时文件并再次读取它们。

如果您将在更多地方使用IO API,则应考虑在IO API上创建自定义包装器并使用集成测试对其进行测试。然后你只能使用包装器来访问文件系统,你可以轻松地模拟它。这样,您就不必为访问文件系统的每个类编写集成测试。您只需测试它是否正确地与您的包装器交互(使用模拟)。

答案 2 :(得分:1)

最好只制作一个临时测试文件,然后检查其内容,类似于this SO question

答案 3 :(得分:1)

我建议你,这是在这种情况下更好的报道之一:

您在注释setUp()

中制作临时方法@Before.

并在此方法中初始化您需要的所有内容。

您在注释releaseResources()中制作了拆解方法 - @After,删除了您的temoorary文件。

如果测试失败,请@Test

new RuntimeException():