As the others stated readObject()
is final
in ObjectInputStream
.
I appreciate that the others did suggest PowerMock to force a mock of this class!
The better solution is to follow that program against interfaces pattern. The method readObject()
is declared in the interface ObjectInput
implemented by ObjectInputStream
So you can change the signature of your class to use the interface ObjectInput
rather than the concrete class ObjectInputStream
.
And mocking the interface ObjectInput
is a piece of cake...
could you add an MCVE of how this is meant to look like? Nobody did this so far. – Tobias Kolb
here it is:
production code:
public class Person {
public Person(String string, String string2, String string3) {
}
}
class ClassUnderTest {
private final ObjectInput objectInput;
public ClassUnderTest(ObjectInput inputStream) {
objectInput = inputStream;
}
public Person readFromObjectStreamAsSideEffect() {
try {
return (Person) objectInput.readObject();
} catch (ClassNotFoundException | IOException e) {
throw new RuntimeException("some meaningful explanation.", e);
}
}
}
Test code
@ExtendWith(MockitoExtension.class) // allows for other runner...
public class ConnectionTest {
@Mock
ObjectInput inputStream;
// @InjectMocks
// compiler will NOT complain if constructor arguments are missing, so I discourage this.
ClassUnderTest cut; // do not initialize here, mock is still NULL.
@BeforeEach
private void setup() {
cut = new ClassUnderTest(inputStream);
}
@Test
public void getPreparedObjectFromInputStreamy() throws Exception {
Person preparedValueObject = new Person("Doe", "John", "123");
when(inputStream.readObject()).thenReturn(preparedValueObject);
Person result = cut.readFromObjectStreamAsSideEffect();
assertEquals(preparedValueObject, result, "hint for reason of failing");
}
}
my particular problem is with writeObject(). Specifically verify(serverInstance).ObjectOutPutStreamToClient.writeObject(someValue);
Do you have a nifty solution for this as well? I recon this is harder because writeObject
is void
. – Tobias Kolb
I's not me but Mockito having a solution for this:
Production code
public class Person {
public Person(String string, String string2, String string3) {
}
// having toString() too improves fail message of test.
}
class ClassUnderTest {
private final ObjectOutput objectOutput;
public ClassUnderTest(ObjectOutput objectOutputStream) {
objectOutput = objectOutputStream;
}
public void writeObjects(List<Person> persons) {
try {
for (Person person : persons) {
objectOutput.writeObject(person);
}
} catch (IOException e) {
throw new RuntimeException("some meaningfull explanation.", e);
}
}
}
test code
@ExtendWith(MockitoExtension.class)
public class ConnectionTest {
@Mock
ObjectOutput outputStream;
ClassUnderTest cut;
@BeforeEach
private void setup() {
cut = new ClassUnderTest(outputStream);
}
@Test
public void getPreparedObjectFromInputStreamy() throws Exception {
List<Person> listToWrite = Arrays.asList(//
new Person("Doe", "John", "123"),
new Person("Doe", "Jane", "456"));
cut.writeObjects(listToWrite);
ArgumentCaptor<Person> passedArgument = ArgumentCaptor.forClass(Person.class);
verify(outputStream, times(listToWrite.size())).writeObject(passedArgument.capture());
assertTrue(passedArgument.getAllValues().contains(listToWrite.get(0)), "hint for reason of failing");
assertTrue(passedArgument.getAllValues().contains(listToWrite.get(1)), "hint for reason of failing");
}
}