Sunday, September 5, 2021

Unit testing with Mockito in Java

Word definitions taken from:
https://stackoverflow.com/questions/346372/whats-the-difference-between-faking-mocking-and-stubbing

  • Stub - an object that contains predefined answers to methods
  • Mock - an object made to satisfy the expected outcome, just like a dummy
  • Fake - an object with a minimum necessary implementation/ return value for a test

Mocking a class

SomeClass someClass = mock(SomeClass.class);
// this creates a mock of a class. but it won't perform any responsibility of that class

Sample class for this tutorial, 'MyClass'

class MyClass {
    public MyClass(S
omeService someService, AnotherClass anotherClass) {
        this.
someService = someService:
        this.anotherClass = anotherClass:
 
  
}
}

We can easily mock these kind of constructor parameters using @Mock annotation

@Mock
SomeService someService;

@Mock
AnotherClass anotherClass;

MyClass myClass;

private initTests() {
    myClass = new MyClass(
someService, anotherClass);
}


If  the class MyClass contains a function defined below,

public String getStudentName () {
    SomeClass someClass = someService.getThatObject();
    Student student = someClass.getStudent();
    return student.getName(); 
}

We can simply test it like below (this is just to understand the concepts, and not the only possible way to test)

@Test
function testGivenWhenThenSomeTestFunctionName () {
    SomeService someService = mock(SomeService.class);
    SomeClass someClass = mock(SomeClass.class);
    Student student = mock(Student.class);
    when( someService.getThatObject() ).thenReturn(someClass);
    when( someClass.getStudent() ).thenReturn(student);
    when( student.getName() ).thenReturn("expectedStringValue");
 
    String result = myClass.getStudentName();
    assertEquals(result, "expectedStringValue"); 
}
 

we can test the same function like below too, without mocking intermediate results

@Test
function testGivenWhenThenSomeTestFunctionName () {
    SomeService someService = mock(SomeService.class);
    SomeClass someClass = mock(SomeClass.class);
    when( someService.getThatObject() ).thenReturn(someClass);
    when( someClass.getStudent() ).thenReturn(student);
    when( someClass.getStudent().getName() ).thenReturn("expectedStringValue");
 
    String result = myClass.getStudentName();
    assertEquals(result, "expectedStringValue"); 
}

even we can use deep stubs to test the above function

@Test
// @TODO: verify this working
function testGivenWhenThenSomeTestFunctionName () {
    SomeService someService = mock(SomeService.class);
    Student student = mock(Student.class, Mockito.RETURNS_DEEP_STUBS);
    SomeClass someClass = mock(SomeClass.class, Mockito.RETURNS_DEEP_STUBS);
     
    student.setName("expectedStringValue");
    someClass.setStudent(student);

    when( someService.getThatObject() ).thenReturn(someClass);

    String result = myClass.getStudentNam();
    assertEquals(result, "expectedStringValue"); 
}


@TODO:
catching expected exceptions

@TODO:
calling real implementation

@TODO:
stub private/protected methods