jeudi 28 juillet 2016

Unit testing serializability of a class with mocks

I am running into a problem where a mock object of another class is not serailizable while unit testing if a particular class is serializable.

Here is a small program that illustrates the issue. I have a Processor class that needs to serializable and RpcClient is a class that is not serializable. To make Processor serializable I have marked rpcClient member variable as transient.

class RpcClient {
  int addr;

  RpcClient(int addr) {
    this.addr = addr;
    // connect to remote service
  }

  // other methods
}

class RpcClientFactory implements Serializable {
  public RpcClient getRpcClient(int addr) {
    return new RpcClient(addr);
  }
}

class Processor implements Serializable {
  final RpcClientFactory rpcClientFactory;
  transient RpcClient rpcClient;

  Processor() {
    this(new RpcClientFactory());
  }

  Processor(RpcClientFactory rpcClientFactory) {
    this.rpcClientFactory = rpcClientFactory;
  }

  public void start(int addr) {
    rpcClient = rpcClientFactory.getRpcClient(addr);
  }

  // other methods
}

Now in order to test the Processor class, I have the following unit test,

@RunWith(JUnit4.class)
public class ProcessorTest {
  private RpcClientFactory mockRpcClientFactory;
  private RpcClient mockRpcClient;

  @Before
  public void setUp() {
    mockRpcClientFactory = mock(RpcClientFactory.class, withSettings().serializable());
    mockRpcClient = mock(RpcClient.class, withSettings().serializable());
    when(mockRpcClientFactory.getRpcClient(any(int.class))).thenReturn(mockRpcClient);
  }

  @Test
  public void testProcessorIsSerializable() {
    Processor p = new Processor(rpcClientFactory);
    p.start();
    // Use some Utils library to serialize and deserialize 
    Utils.deserializeFromByteArray(Utils.serializeToByteArray(p));

    assert(true);
  }
}

Running the test fails with an exception,

Caused by: java.io.InvalidClassException: ProcessorTest$RpcClient$$EnhancerByMockitoWithCGLIB$$5db6cf07; no valid constructor

Of course the problem goes away if I add a no-arg constructor to RpcClient but lets say it is a third-party library to which I don't have access to. I understand that Mockito clearly mentions, The mock can be serialized assuming all the normal serialization requirements are met by the class and in my case RpcClient doesn't meet the requirements.

But if you look at it, even though my code doesn't expect RpcClient to be serializable (marked transient), my unit test forces me to. Is there a way to get around this in my test class?

Aucun commentaire:

Enregistrer un commentaire