Search code examples
javamockinginitializationfinaljmockit

How to mock final instance variable in a class using JMockit


I am trying to use JMockit to do behavior test. In one of the test, I need to call a method in the final object. However, the final object is not initialized (null object) and I don't know how to initialize it in the test (since it is defined final). I cannot found the solution to mock a final instance with in a class. See the test first, and I will explain the code.

public class NetworkClientTest {
    @Cascading @Capturing ServerRequestHandler nrh;

    @Test
    public void testRequestSimilar(){
      //define test parameters
      String smiles = "abcd";
      float t = (float) 0.1;
      final Map<String, Object> parameters = new HashMap<String, Object>();
      String smi = StringEscapeUtils.unescapeJava(smiles);
      parameters.put("smiles",smi );
      parameters.put("tanimoto", t);
      //end define test parameters
      //try to initialize NetworkClient object
      new MockUp<NetworkClient>() {
        @Mock
        public void $init(){

        }   
      };
      NetworkClient nc = new NetworkClient();
      new Expectations(){
        //ServerRequestHandler nrh;
        {
            nrh.sendRequest("get_similar_entries", parameters);
        }

    };
    //when nc.requestSimilarEntries is called, nc.nrh.sendRequest will be expected. 
    nc.requestSimilarEntries(smiles, t); 
}

where nrh is a final instance defined in nc (NetworkClient class) and nc.nrh.sendRequest will be called after nc.requestSimilarEntries is called.

public class NetworkClient {
  private final ServerRequestHandler nrh = new ServerRequestHandler();
  ... 
   public void requestSimilarEntries(String smiles, float tanimoto) {
    // Set up parameters
    Map<String, Object> parameters = new HashMap<String, Object>();
    String smi = StringEscapeUtils.unescapeJava(smiles);
    parameters.put("smiles",smi );
    parameters.put("tanimoto", tanimoto);

    // Send a request to the handler
    nrh.sendRequest("get_similar_entries", parameters);
}

The problem is I cannot get the final ServerRequestHandler nrh initialized in the test. The test result says 'missing invocation'. I checked in debug mode (in Eclipse) and nc.nrh is null all the time.

Please let me know if you need more information and thank you for your help!


Solution

  • You are mocking NetworkClient's constructor, which also means that the instance variable are not instantiated. You need to instantiate the nrh variable. For example:

      new MockUp<NetworkClient>() {
        @Mock
        public void $init(Invocation inv){
            NetworkClient client = inv.getInvokedInstance();
            Deencapsulation.setField(client, "nrh", new ServerRequestHandler());
        }   
      };
    

    Now you probably also want to mock the ServerRequestHandler class, in which case you can simply create a new MockUp:

      new MockUp<NetworkClient>() {
      };
    
      new MockUp<ServerRequestHandler>() {
      };
    

    Note: I have not used jmockit in a while so it might not work but probably worth trying.