2

I'm beginner, and keep yourself in hands. I need to test this method - write/read to/from file. Can You get advice? How better I can do this, use only junit test or better EasyMock? What can you recomend to do?

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);
}
}

I wrote little more code, and You can understend situations better. I hope You can recomend how to test this(maybe you can show two variants).

catch23
  • 17,519
  • 42
  • 144
  • 217
  • 1
    Instead of mocking the classes, it is far simple to use temporary files. – Peter Lawrey Jan 06 '13 at 09:50
  • I would have `figureReader` return a `List` and I would always printout the exception unless you are adding, not discarding information. ;) I would write any additional information to `System.err` as thee is where Exceptions are written to by default. – Peter Lawrey Jan 06 '13 at 09:52

3 Answers3

3

You can completely circumvent the usage of disk I/O, by using memory I/O. You don't need EasyMock for that, simply different input and output streams. You can assert that your methods are working correctly with JUnit by checking the resulting output stream (write) and resulting list of FigureGeneral objects (read).

Step by step:

1) Inject the outputstream that the write methods will use.

You could add another "write" method that is called by your already existing "write" method that takes an output stream with a signature like this:

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

Your original write method would wrap the above method by calling that method like this:

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

2) Repeat the above trick for the read method using InputStream.

That would give you a read method with a signature like this:

private ArrayList<FigureGeneral> figureReader(InputStream inputStream);

3) Now write JUnit tests that use ByteArrayInputStream and ByteArrayOutputStream and call the above methods.

You can check the results of your write method by calling toByteArray() on your ByteArrayOutputStream and asserting the results. You can check the results of your read method by asserting the values in the List after passing it a certain ByteArrayInputStream.

Here's a (pseudo) method you could add to your test class to assert that a lists of FigureGeneral objects of differing natures can be written to an output stream, read back from an input stream and be equal.

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) This will give you a pretty good test coverage. Still, if you would like to achieve 100% test coverage you would still have to test the orignal write and readFigure methods that have now become wrappers.

The original methods do nothing more than redirect to their namesake which uses the input and output stream. You could check their redirect using EasyMock by overriding (or implementing if you put these methods behind an interface) the two redirect methods and asserting that they receive proper FileInputStream and FileOutputStream objects. You'll need some temporary files for that though since the FileOutputStream constructor needs an existing file. I don't see any major problems using temporary files in a testcase however.

Lodewijk Bogaards
  • 19,777
  • 3
  • 28
  • 52
1

It might be better to just make a temporary test file and then check its contents, similar to this SO question.

Community
  • 1
  • 1
chm
  • 1,519
  • 13
  • 21
1

My suggest to you, this is one of better coverage at this situations:

You make temporary method setUp() in annotation @Before.

And initialize all what you need in this method.

You make teardown method - releaseResources() in annotation @After, where you delete your temoorary file.

And make @Test for all oppotunity situations, if test fail throw new RuntimeException():

public class AbsFigureTest {

    public static final String defaultTestPath = "unittest.tmp";
    private List<FigureGeneral> inputFigures;
    private List<FigureGeneral> outputFigures;
    private DeepCompare deepCompare;

    @Before
    public void setUp() throws FigureGeneralFilesFoundException,
            FigureGeneralFormatException {
        inputFigures = absFigure.generateRandomFigures(5);
        absFigure.write(defaultTestPath, inputFigures);
        outputFigures = absFigure.figureReader(defaultTestPath);
        deepCompare = new DeepCompare();
}

    @After
    public void releaseResources() {
        new File(defaultTestPath).delete();
    }

    @Test
    public void assertEquals_FigureGeneralLists_ReturnZero() {
        for (int i = 0; i < inputFigures.size(); i++) {
            FigureGeneral inputValue = inputFigures.get(i);
            FigureGeneral outputValue = outputFigures.get(i);

            if (deepCompare.compare(inputValue, outputValue) != 0)
                throw new RuntimeException("not equal");
        }

    }

    @Test
    public void testDeepCompRectangle_EqualResult_ReturnZero() {
        FigureGeneral oneFigure = new Rectangle(2.0, 2.0, "rectangle");
        FigureGeneral twoFigure = new Rectangle(2.0, 2.0, "rectangle");
        int result = deepCompare.compare(oneFigure, twoFigure);
        assertTrue("expected to be equal", result == 0);
    }

    @Test
    public void testDeepCompTriangle_EqualResult_ReturnZero() {
        FigureGeneral oneFigure = new Triangle(2.0, 2.0, "rectangle");
        FigureGeneral twoFigure = new Triangle(2.0, 2.0, "rectangle");
        int result = deepCompare.compare(oneFigure, twoFigure);
        assertTrue("expected to be equal", result == 0);
    }

    @Test
    public void testDeepComp_GreaterThan_ReturnOne() {
        FigureGeneral oneFigure = new Triangle(2.0, 2.0, "triangle");
        FigureGeneral twoFigure = new Rectangle(1.0, 1.0, "rectangle");
        int result = deepCompare.compare(oneFigure, twoFigure);
        assertTrue("expected to be greater than", result >= 1);

        if (deepCompare.compare(oneFigure, twoFigure) != 0)
            throw new RuntimeException("not equal");
    }
}