Testing with Mockito and PowerMockito

Testing with Mockito and PowerMockito

Introduction

Mockito is a mocking framework. i.e it simulates the behavior of a real method/object. In Simple Term: It mocks/replicates the main method/object by creating its dummy functionality.

Why do we need a mocking framework ?
We want to test the functionality of a class in isolation in a controlled way. However, there are several obstacles

  • Real objects can be slow (like database connection).
  • Objects contain lots of dependencies and these are often complex to configure and instantiate.
  • Sometimes, the code may not be coded yet and only interface exists.
  • And if the code results into side effects - like code sending an email upon invocation.

In this situations, we want someone to imitate the exact same behavior our real method/objects possess without ever executing the original method.
This is exactly what Mockito does.

Understanding concept

1. Diagram overview

mockito-steps.png

2. Terms and concepts

@InjectMocks:
The Class under test and inject the mock object into it.

@Mock:
Mock this dependency for the class that is under test.

Stubbing:
Return a given value when a specific method is called.

  • Act as a replacement to real code
  • Fake the behavior of code not yet developed
  • simulate controlled environment
  • Record information about method calls and also verify call

Stubbing example - Mockito.when() in conjunction with: eg: when(“method()”).thenReturn(“value”);

  • thenReturn(..)
  • thenThrow(..)
  • thenCallRealMethod(..)
  • thenAnswer(..)

Spies:
It Behaves in the same way as a normal instance and allow us to call all the normal methods of the object while still tracking every interaction.
Mockito.spy or @Spy

Assert:
Check or assure that the method call returned expected value.

Verify:
We use Mockito.verify(..) method to check whether an intended mock operation was called or not.

  • times(n)
  • atLeastOnce()
  • atLeast(n)
  • atMost(n)
  • never()

3. Code Overview

mockito-steps-code.png

Code implementation
Include Dependency (in “pom.xml” or build.gradle) —

org.mockito.mockito-core*

More Mockito Features:

  • Argument matchers
  • Verification Order
  • Argument capturing

Argument matchers:

Mockito.when( userRepository.findByCity(Matchers.anyString())).thenReturn(user);
// eq(), anyInt(), anyDouble(), contains(), startsWith()

Verification Order:

Mockito.inOrder()

Argument capturing:

// @Captor private ArgumentCaptor<Person> personCaptor;
// OR
ArgumentCaptor<Person> personCaptor= ArgumentCaptor.forClass(Person.class);
// -----------------------------------
verify(mockObject).doSomething(personCaptor.capture());
assertEquals(“John”, personCaptor.getValue().getName());

Code Git repo: ashrawan/crud-jpa-with-test
Official Site: Official Mockito Site

PowerMockito

Mockito create mock object using proxy pattern.

Since proxy pattern is created by extending it, "mockito cannot mock static, private, final methods, and constructor.

The bytecode manipulation has to be done at runtime to mock such methods. So we use library called PowerMockito which create mock object using proxy pattern and add further behaviour to provide additional facilities to mock these methods.

Test we want to test:

@Service
public class UserServiceImpl implements User {

  // constructor
  public UserServiceImpl() {
      System.out.println("Spy Instantiate real object, constructor called");
  }

  public String getPublicValue() {
      return "Hello";
  }

  private int getSome(int a, int b) {
      return a+b;
  }

  @Override
  public int getSecret() {
      return getSome(1, 2);
  }

  public static String getClassCode() {
      return "User000";
  }

  public final String getInfo(){
      return "final method";
  }

}

Test Class:

@RunWith(PowerMockRunner.class)
@PrepareForTest(UserServiceImpl.class)
public class UserServiceTest {

}

Static Method:

@Test
public void testStaticMethod(){

mockStatic(UserServiceImpl.class);
when(UserServiceImpl.getClassCode()).thenReturn("User000");
assertEquals("User000", UserServiceImpl.getClassCode());
}

Private Method:

@Test
public void testPrivateMethod() throws Exception{

UserServiceImpl userServiceImplSpy = PowerMockito.spy(new UserServiceImpl());
when(userServiceImplSpy, "getSome", anyInt(), anyInt()). thenReturn(30);
assertEquals(30, userServiceImplSpy.getSecret());
}

Final Method:

@Test
public void testFinalMethod() throws Exception{

UserServiceImpl userServiceImplMock = PowerMockito.mock(UserServiceImpl.class);
when(userServiceImplMock.getInfo()).thenReturn("final method");
assertEquals("final method", userServiceImplMock.getInfo());
}

Constructor:

@Test
public void testConstructor() throws Exception{

UserServiceImpl userServiceImplMock = mock(UserServiceImpl.class);
whenNew(UserServiceImpl.class).withNoArguments().thenReturn(userServiceImplMock);
UserServiceImpl userServiceImp = new UserServiceImpl();
verifyNew(UserServiceImpl.class).withNoArguments();
}

Public Method:

@Test
public void testPublicMethod() throws Exception{

UserServiceImpl userServiceImplMock = mock(UserServiceImpl.class);
when(userServiceImplMock.getPublicValue()).thenReturn("Hello");
assertEquals("Hello", userServiceImplMock.getPublicValue());
}

Code Git repo: ashrawan/Demo-PowerMockito
Official site: Official PowerMockito Site