What I'm trying to do
I have a server class that has intentionally no arguments passed to it and want to test it with Mockito.
If you want to check out the full source code on Github:
Server.class
public class Server extends Thread {
private Other other;
ObjectInputStream fromClient;
ObjectOutputStream toClient;
public Server(){
this.other = new Other(foo, bar);
}
@Override
public void run(){
try{
ServerSocket serverSocket = new ServerSocket(1337);
Socket socket = serverSocket.accept();
fromClient = new ObjectInputStream(socket.getInputStream());
toClient = new ObjectOutputStream(socket.getOutputStream());
while(true) {
int command = (Integer) fromClient.readObject();
switch (command) {
case 0x1:
//add
//...
break;
case 0x2:
//get server data
toClient.writeObject(other.getSomething());
break;
case 0x3:
//delete
//...
break;
default:
break;
}
}
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
Thread t = new Server();
t.start();
}
}
The Problem
I understand that Mockito can't mock final classes, such as ObjectOutputStream and ObjectInputStream.
This is exactly where I run into Problems.
So far, my test is failing with NullPointerException on line
when(server.fromClient.readObject()).thenReturn(0x2);
.
This is typical for Mockito, when running into final methods.
ServerTest.class
@Test
void run() throws IOException, ClassNotFoundException {
//given
Other other = new Other(foo, bar);
Server server = mock(Server.class);
//when
when(server.fromClient.readObject()).thenReturn(0x2);
server.start();
//then
verify(server).toClient.writeObject(other.getSomething());
}
What I tried
It was suggested in other posts that it's possible to circumvent the final-problem, by changing the signature of the class under test by implementing the interface ObjectInput
and therefore mock it anyway.
However in the proposed approach it's unclear how to operate when not passing ObjectOutputStream
as an argument to the class under test.
Also, how to operate when you have the ObjectInputStream
directly controlling a response of an ObjectOutputStream
, as seen with my case
structure, which is not untypical for TCP client/server applications.
So far I'm under the impression that my test would work, would it not be for the final keyword in the signature of ObjectOutputStream
. Correct me here if I'm wrong.
Q: "Why am I not passing the streams to the server?" A: Because I don't need them anywhere else.
It's really a last ditch effort to do so and I will if I have to, but I would rather not.