Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unit Tests How to Mock Repository Using Mockito

I am having an issue with stubbing my repository. I was suggested to just create another application.properties (which I have not done) and to use an in-memory database like H2. I was wondering though if I can just stub the call so when myDataService.findById(id) is called instead of it attempting to get that from the database just a mocked object can be returned?

I am new to writing mocks for my unit tests and spring boot in general so maybe I am missing something. Code below (tried to simplify and made names generic for posting here).

My test class

public class MyServiceImplTest 
{
    private MyDataService myDataService;
    private NyService myService;
    private MyRepository myRepository;

    @Before
    public void setUp() {
        myDataService = Mockito.mock(MyDataServiceImpl.class);
        myService = new MyServiceImpl(myDataService);
    }

    @Test
    public void getById_ValidId() {
        doReturn(MyMockData.getMyObject()).when(myDataService).findById("1");
        when(myService.getById("1")).thenReturn(MyMockData.getMyObject());
        MyObject myObject = myService.getById("1");

        //Whatever asserts need to be done on the object myObject 
    }
}

Class used for making the service call to the data layer

@Service
public class MyServiceImpl implements MyService {
    MyDataService myDataService;

    @Autowired
    public MyServiceImpl(MyDataService myDataService) {
        this.myDataService = myDataService;
    }

    @Override
    public MyObject getById(String id) {
        if(id == null || id == "") {
            throw new InvalidRequestException("Invalid Identifier");
        }

        MyObject myObj;
        try {
            myObj = myDataService.findById(id);
        }catch(Exception ex) {
            throw new SystemException("Internal Server Error");
        }

        return myObj;
    }
}

This is where I am having the issue in my test. When the findById() method is called, the variable repository is null so when trying to do repository.findOne(id) it throws an exceptionn. This is what I am attempting to mock, but the repository is giving me issues.

@Repository
@Qualifier("MyRepo")
public class MyDataServiceImpl {

    @PersistenceContext
    private EntityManager em;

    private MyRepository repository;

    @Autowired
    public MyDataServiceImpl(MyRepository repository) {
        super(repository);
        this.repository = repository;
    }

    public MyObject findById(String id) {
        P persitentObject = repository.findOne(id);
        //Calls to map what persitentObject holds to MyObject and returns a MyObject 
    }
}

Code for MyRepository here just to show it's an empty interface that extends CrudRepository

public interface MyRepository extends CrudRepository<MyObjectPO, String>, JpaSpecificationExecutor<MyObjectPO> {

}
like image 676
Dani Avatar asked Jun 27 '18 01:06

Dani


People also ask

How do you make a mock in Mockito?

Mockito mock method We can use Mockito class mock() method to create a mock object of a given class or interface. This is the simplest way to mock an object. We are using JUnit 5 to write test cases in conjunction with Mockito to mock objects.

Is Mockito used for unit testing?

Mockito is a Java-based framework used for unit testing of Java applications. This mocking framework helps in the development of testable applications.


1 Answers

Let me begin by saying you are on the right track by using Constructor Injection and not Field Injection(which makes writing tests with mocks much simpler).

public class MyServiceImplTest 
{
    private MyDataService myDataService;
    private NyService myService;

    @Mock
    private MyRepository myRepository;

    @Before
    public void setUp() {
        MockitoAnnotations.initMocks(this); // this is needed for inititalizytion of mocks, if you use @Mock 
        myDataService = new MyDataServiceImpl(myRepository);
        myService = new MyServiceImpl(myDataService);
    }

    @Test
    public void getById_ValidId() {

        doReturn(someMockData).when(myRepository).findOne("1");
        MyObject myObject = myService.getById("1");

        //Whatever asserts need to be done on the object myObject 
    }
}

The call goes all the way from your service --> dataService. But only your repository calls are mocked.
This way you can control and test all the other parts of your classes(both service and dataService) and mock only repository calls.

like image 162
pvpkiran Avatar answered Sep 22 '22 09:09

pvpkiran