Unit-testing – Unit test a class that sequentially calls other classes

mockingunit testing

Hi i have a class like this

class MyClass {

  private ExternalClass1 ex1;
  private ExternalClass2 ex2;
  private ExternalClass3 ex3

public String doSomething(String arg1){ 
 val1=ex1.invoke(arg1); 
 val2=ex2.call(val1); 
 result=ex3.doit(val2);
 return result;
}    

}

unit test of this method

@Test
void doSometing(){
   ExternalClass1 ex1=mock(ExternalClass1);
   ExternalClass2 ex2=mock(ExternalClass2);
   ExternalClass3 ex3=mock(ExternalClass2);

when(ex1.invoke(arg1)).thenReturn(val1);
when(ex2.call(val1)).thenReturn(val2);
when(ex3.doit(val2)).thenReturn(result);

Myclass myClass=new MyClass(ex1,ex2,ex3);

assertEquals(result,myClass.doSomething(arg1))
}

The test code of this method seems to be a simple repetition of the code itself, but more complex.
Does the test of this kind of class whose role is to control other classes brings any value?

Thank's

Best Answer

Does it bring any value?

Yes - it is testing interaction.

If you have already unit tested the functionality of the three methods being called, then they are guaranteed to perform correctly. This kind of test is a State Test; call the method and check you receive the correct result.

But here you want to perform an Interaction Test; one that tests that some methods were called correctly (you may not know what these methods do to the data, so you cannot test the result's value consistently).

To perform an interaction test, change your mocks to add an incrementor to each method, then assert that the incremented variables are what you expected:

How you implement the incrementor will depend on how you have created your classes and how you are mocking.

As a brief seudo example:

@Test
void doSomething()
{
    ExternalClass1 ex1=mock(ExternalClass1);
    ExternalClass2 ex2=mock(ExternalClass2);
    ExternalClass3 ex3=mock(ExternalClass2);

    int ex1Count = 0;
    int ex2Count = 0;
    int ex3Count = 0;

    when(ex1.invoke(arg1)).do(ex1Count++).thenReturn(val1);
    when(ex2.call(val1)).do(ex2Count++).thenReturn(val2);
    when(ex3.doit(val2)).do(ex3Count++).thenReturn(result);

    Myclass myClass = new MyClass(ex1,ex2,ex3);

    myClass.doSomething(arg1);

    assertEquals(1, ex1Count);
    assertEquals(1, ex2Count);
    assertEquals(1, ex3Count);

    // assertEquals(2, ex1Count); // If for example ex3 utilises ex1 once (and you know that it should)...
}
Related Topic