0

Purpose: To build a stickynote application using TDD (which I recently learned and now actively regretting)

Problem: I expect all the "Note"s to be serialized and deserialized by thier own individual classes. And I wish to use the TDD approach, but I am unable to even test the happy path of the NoteReader class (deserializer) let alone the corner cases.

Here is the Code:

package com.domainname.applicationname;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.util.List;

public class NoteReader {
    private final FileInputStream fileInputStream;

    public NoteReader(FileInputStream fileInputStream) {
        this.fileInputStream = fileInputStream;
    }

    @SuppressWarnings("unchecked")
    public List<Note> load() {
        ObjectInputStream objectInputStream = null;
        List<Note> output = null;
        try {
            objectInputStream = new ObjectInputStream(fileInputStream);
            output = (List<Note>) objectInputStream.readObject();
            objectInputStream.close();
        } catch (ClassNotFoundException | IOException e) {
            e.printStackTrace();
        }
        return output;
    }
}

and here is the unit testing code:

package com.domainname.applicationname;

import org.junit.*;
import org.mockito.Mockito;

import java.io.*;
import java.util.Arrays;
import java.util.List;

public class NoteReaderTest {
    private FileInputStream dummyFileInputStream;
    private NoteReader noteReaderDummy;

    private List<Note> expectedOutput = Arrays.asList(
            new Note("some written text"),
            new Note("some other written text", NoteColor.lightGreen)
    );

    private ByteArrayOutputStream byteArrayOutputStream;
    private ObjectOutputStream objectOutputStream;
    private byte[] bytesToBeDeserialized;

    @Before
    public void setUp() throws IOException {
        dummyFileInputStream = Mockito.mock(FileInputStream.class);
        noteReaderDummy = new NoteReader(dummyFileInputStream);

        byteArrayOutputStream = new ByteArrayOutputStream();
        objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
    }

    @After
    public void tearDown() throws IOException {
        noteReaderDummy = null;
        byteArrayOutputStream.flush();
        objectOutputStream.flush();
        objectOutputStream.close();
    }

    @Test
    public void shouldLoadTheListOfNotes() throws IOException {
        //given
        objectOutputStream.writeObject(expectedOutput);
        bytesToBeDeserialized = byteArrayOutputStream.toByteArray();
        int intValueOfByteArray = dummyFileInputStream.read(bytesToBeDeserialized);
        //when
        Mockito.when(
                dummyFileInputStream.read()
        ).thenReturn(
                intValueOfByteArray
        );

        //then
        Assert.assertEquals(
                "the notes have not been loaded",
                expectedOutput,
                noteReaderDummy.load()
        );
    }
}

This has b/me an infinite loop and it's driving me nuts.

Question: How do I test a deserialization class? What am I doing wrong in the above code?

NegassaB
  • 379
  • 7
  • 24
  • *which I recently learned and now actively regretting* You regred that you have learnt this or that you should have learned this some time ago ?:) – Antoniossss Jan 14 '19 at 15:39
  • try not to reinvent the wheel when possible. any reason you arent just using spring / jackson for serialization / deserialization? https://stackoverflow.com/questions/18524524/passing-json-data-to-a-spring-mvc-controller – Phil Ninan Jan 14 '19 at 17:49
  • @Antoniossss I am not regretting that I learnt it, I am regretting that I didn't learn it some time ago and I am regretting I decided to put it to use. – NegassaB Jan 15 '19 at 12:33
  • @PhilNinan This is a simple app, therefore why should I bother with using a jackhammer to hammer in a nail? – NegassaB Jan 15 '19 at 12:34
  • @GaddBWeldesenbet I think because you said this is "a simple app" makes even more sense to use Spring. it only takes 5-10 mins to setup a complete web app in eclipse using Spring Boot. You can spend less time writing your own serializer and more time working on core functionality. https://dzone.com/articles/creating-a-spring-boot-project-with-eclipse-and-ma – Phil Ninan Jan 15 '19 at 16:33
  • @PhilNinan it's a stickynote app, I still don't see the reason to use a jackhammer to hit a nail. Plus I would have to learn spring before using it. Isn't there any examples that show how to test I/O operations in java? – NegassaB Jan 16 '19 at 12:21

2 Answers2

0

I would add a file to your app and just load that for testing purposes.

@Test
public void givenUsingPlainJava_whenConvertingFileToInputStream_thenCorrect() 
  throws IOException {
    File initialFile = new File("src/main/resources/sample.txt");
    InputStream targetStream = new FileInputStream(initialFile);
}

https://www.baeldung.com/convert-file-to-input-stream

Phil Ninan
  • 1,108
  • 1
  • 14
  • 23
0

For anybody else that might face the same issue, override the hashCode() and equals() method of the Note class to work like I intend it to. Instantiate the List to ArrayList or LinkedList. This solved it for me. The one thing I couldn't figure out is how to use Mockito with it. So I took the advice of @PhilNinan and use a TemporaryFolder with a tempFile. Then serialized into that file and read that file (not ideal but couldn't find another way). The NoteReader:

package com.somedomainname.someapplication;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.util.ArrayList;
import java.util.List;

class NoteReader {
    private final FileInputStream fileInputStream;

    NoteReader(FileInputStream fileInputStream) {
        this.fileInputStream = fileInputStream;
    }

    @SuppressWarnings("unchecked")
    List<Note> load() throws IOException {
        ObjectInputStream objectInputStream = null;
        List<Note> output = new ArrayList<>();

        try {
            objectInputStream = new ObjectInputStream(fileInputStream);
            while (fileInputStream.available() != 0) {
                Note n = (Note) objectInputStream.readObject();
                output.add(n);
            }

        } catch (ClassNotFoundException | IOException e) {
            fileInputStream.close();
            assert objectInputStream != null;
            objectInputStream.close();

            e.printStackTrace();
        }
        return output;
    }

}

The NoteReaderTest class:

package com.somedomainname.someapplicationname;

import org.junit.*;
import org.junit.rules.TemporaryFolder;

import java.io.*;
import java.util.ArrayList;
import java.util.List;

public class NoteReaderTest {
    private NoteReader noteReaderDummy;

    private ObjectOutputStream objectOutputStream;

    @Rule
    public TemporaryFolder temporaryFolder = new TemporaryFolder();

    private File tempFile;

    private static List<Note> inputList = new ArrayList<>();
    static {
        inputList.add(new Note("some written text"));
        inputList.add(new Note("some other written text", NoteColor.lightGreen));
    }

    private static List<Note> anotherList = new ArrayList<>();
    static {
        anotherList.add(new Note("qazwsxedcrfv"));
        anotherList.add(new Note("qwertyuiopasdfghjkl", NoteColor.lightRed));
    }

    @Before
    public void setUp() throws IOException {
        tempFile = temporaryFolder.newFile("someBullshit.ser");
        objectOutputStream = new ObjectOutputStream(new FileOutputStream(tempFile));

        for(Note n : inputList) {
            objectOutputStream.writeObject(n);
        }

        noteReaderDummy = new NoteReader(new FileInputStream(tempFile));

    }

    @After
    public void tearDown() throws IOException {
        objectOutputStream.flush();
        objectOutputStream.close();
        tempFile = null;
        temporaryFolder = null;
        noteReaderDummy = null;

    }

    /**
     * This test method tests the happy path of the NoteReader.load() method.
     * @throws IOException
     */

    @Test
    public void shouldLoadTheListOfNotes() throws IOException {
        //given

        //then
        List<Note> output = noteReaderDummy.load();
        Assert.assertEquals(
                "the notes have not been loaded",
                inputList,
                output
        );

    }

    /**
     * This test method is responsible for confirming that the output of the
     * NoteReader.load() method doesn't stray from the expected one.
     * @throws IOException
     */

    @Test
    public void shouldNotLoadTheOtherListOfNotes() throws IOException {
        //given

        //then
        List<Note> output = noteReaderDummy.load();
        Assert.assertNotEquals(
                "it loaded the wrong fucking list",
                anotherList,
                output
        );

    }

    /**
     * this test method is responsible for checking that the output of
     * the method NoteReader.load() is not null
     * @throws IOException
     */

    @Test
    public void shouldNotBeNull() throws IOException {
        //given

        //then
        List<Note> output = noteReaderDummy.load();
        Assert.assertNotNull(
                "fuck it's null",
                output
        );
    }
}
NegassaB
  • 379
  • 7
  • 24