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?
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);
}