Mocking dependencies without using Mockito Framework

In this post, we will learn how we can create dummy implementation of a dependency class and use it in our Unit Test.

Let's consider following UserService class.

UserService.java

package com.devnips.mockitojunit5.service;

import com.devnips.mockitojunit5.model.User;
import com.devnips.mockitojunit5.repository.UserRepository;
import org.springframework.stereotype.Service;

import java.util.Optional;

@Service
public class UserService {

    private final UserRepository userRepository;

    public UserService(UserRepository userRepository) {
        this.userRepository = userRepository;
    }

    /**
     * Save a user in database
     *
     * @param id
     * @return
     */
    public Optional findById(Long id) {
        if (id == null) {
            throw new RuntimeException("Id is required");
        }
        return userRepository.findById(id);
    }
}

This class is a Spring bean and has dependency on UserRepository interface. UserRepository interface is again a Spring JPA bean. Spring JPA provides easy implementation of JPA based repositories to access database. Spring JPA uses auto configurations to initialize database connections. 

UserRepository.java

package com.devnips.mockitojunit5.repository;

import com.devnips.mockitojunit5.model.User;
import org.springframework.data.jpa.repository.JpaRepository;

public interface UserRepository extends JpaRepository {
}

While testing UserService class, we need to remove dependency on UserRepository class, since we only want to test that the code in UserService class is working correctly. For testing any dependency class, we will write separate Unit Tests for that class. 

In Unit Tests we isolate each class and test its functionality individually.

To achieve this isolation we replace the actual implementation of the dependency class with a dummy one and override the methods to return static values as per our test requirement.

Below is an example, that provides dummy implementation of the UserRepository class and tests the findOneById(Long) method of UserService class.

UserRepository.java

package com.devnips.mockitojunit5.service;

import com.devnips.mockitojunit5.model.User;
import com.devnips.mockitojunit5.repository.UserRepository;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.springframework.data.domain.Example;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;

import java.util.List;
import java.util.Optional;

public class UserServiceNoMockitoTest {

    private UserService userService;

    private MockUserRepository mockUserRepository = new MockUserRepository();

    @Test
    void findOneById_valid_id() {
        // Setup dummy behaviour
        userService = new UserService(new MockUserRepository() {
            @Override
            public Optional<User> findById(Long id) {
                if (id == 100L) {
                    return Optional.of(new User(id));
                } else {
                    return Optional.empty();
                }
            }
        });

        // When test method is called
        Optional<User> optionalUser = userService.findById(100L);

        // Then we should get non empty value
        Assertions.assertTrue(optionalUser.isPresent());
    }

    /**
     * Creating a dummy implementation of UserRepository.
     */
    class MockUserRepository implements UserRepository {

        @Override
        public List<User> findAll() {
            return null;
        }

        @Override
        public List<User> findAll(Sort sort) {
            return null;
        }

        @Override
        public Page<User> findAll(Pageable pageable) {
            return null;
        }

        @Override
        public List<User> findAllById(Iterable<Long> iterable) {
            return null;
        }

        @Override
        public long count() {
            return 0;
        }

        @Override
        public void deleteById(Long aLong) {

        }

        @Override
        public void delete(User user) {

        }

        @Override
        public void deleteAll(Iterable<? extends User> iterable) {

        }

        @Override
        public void deleteAll() {

        }

        @Override
        public <S extends User> S save(S s) {
            return null;
        }

        @Override
        public <S extends User> List<S> saveAll(Iterable<S> iterable) {
            return null;
        }

        @Override
        public Optional<User> findById(Long aLong) {
            return Optional.empty();
        }

        @Override
        public boolean existsById(Long aLong) {
            return false;
        }

        @Override
        public void flush() {

        }

        @Override
        public <S extends User> S saveAndFlush(S s) {
            return null;
        }

        @Override
        public void deleteInBatch(Iterable<User> iterable) {

        }

        @Override
        public void deleteAllInBatch() {

        }

        @Override
        public User getOne(Long aLong) {
            return null;
        }

        @Override
        public <S extends User> Optional<S> findOne(Example<S> example) {
            return Optional.empty();
        }

        @Override
        public <S extends User> List<S> findAll(Example<S> example) {
            return null;
        }

        @Override
        public <S extends User> List<S> findAll(Example<S> example, Sort sort) {
            return null;
        }

        @Override
        public <S extends User> Page<S> findAll(Example<S> example, Pageable pageable) {
            return null;
        }

        @Override
        public <S extends User> long count(Example<S> example) {
            return 0;
        }

        @Override
        public <S extends User> boolean exists(Example<S> example) {
            return false;
        }
    }
}

0 comments:

Post a Comment