Search code examples
javaspringspring-bootjunit

Unit testing code having database dependency


I am using Junit4 in Spring boot application. I am able to write tests that don't have dependency on database but facing trouble in testing code having DB dependency. Like below test is for a method written in service class that return a Country object when a country matches with the country name provided in method param. When I run this test, result always assert as null as it find no data in underlying list utilized for searching Countries.

Test Method:

@Test
public void test_returns_country_by_name() {
    CountryDao mockCountryDao = Mockito.mock(CountryDao.class);

    // Arrange
    CountryServiceImpl countryService = new CountryServiceImpl(mockCountryDao);
    String name = "Canada";

    // Act
    Country result = countryService.getCountryByName(name);

    // Assert
    assertNotNull(result);
    assertEquals(name, result.getName());
}

Service Class code:

@Service("countryService")
public class CountryServiceImpl implements CountryService {

    private final CountryDao countryDao;

    public CountryServiceImpl(CountryDao countryDao) {
        this.countryDao = countryDao;
    }

    public Country getCountryByName(String name) {
        return findCountryByCondition(c -> name.equalsIgnoreCase(c.getName()));
    }

    private Country findCountryByCondition(Predicate<Country> condition) {
        return getAllCountries().stream().filter(condition).findFirst().orElse(null);
    }

    public List<Country> getAllCountries() {
        List<Country> countries = countryDao.getAllCountries();    
        return countries;
    }
}

Here, unless getAllCountries method return a list containing "Canada" Country object till then test will get null only.

I want to understand is there any to fix this issue without using an actual database (In-memory or other). Also is my test approach right, or there is some other way people test this kind of code?


Solution

  • As mentioned already, when using mocks, you really should also setup the data and expectations of it. One way of doing so is with the Mockito when keyword where you programmatically provide behavior. What do I want this mock to return when a certain method is being called, perhaps with certain arguments (if applicable). Do I want to return data? Or do I perhaps want to throw an exception to simulate and verify my error handling?
    It's this essential part that is missing from your test setup.

    
    @Test
    public void test_returns_country_by_name() {
        CountryDao mockCountryDao = Mockito.mock(CountryDao.class);
    
        // Arrange
        CountryServiceImpl countryService = new CountryServiceImpl(mockCountryDao);
        Country belgium = new Country("Belgium");
        Country canada = new Country("Canada");
        org.mockito.when(mockCountryDao.getAllCountries()).thenReturn(List.of(belgium, canada));
    
        // Act
        Country result = countryService.getCountryByName("Canada");
    
        // Assert
        assertNotNull(result);
        assertEquals(canada, result);
    }