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