I'm trying to implement unit test for a Spring boot project.
I'm new with unit testing in Java and I learned that I can test my project in the service layer. So I have this:
@Mock
private ICampusRepository campusRepository;
@InjectMocks
private CampusServiceImplementation campusService;
private List<Campus> campusList = new ArrayList<>();
@BeforeEach
void setUp() {
MockitoAnnotations.openMocks(this);
campusList.add(new Campus(1, "Campus Name 1", "ACTIVE"));
campusList.add(new Campus(2, "Campus Name 2", "ACTIVE"));
campusList.add(new Campus(3, "Campus Name 3", "INACTIVE"));
}
Then, for testing I have some very basic test:
@Test
void getAllCampus() {
when(campusRepository.findAll()).thenReturn(campusList);
assertNotNull(campusService.getAllCampus());
}
I want to make a test to verify if certain method returns a list of campus with "ACTIVE" attribute only, I'm trying to do this:
@Test
void listAllActiveCampus() {
when(campusRepository.findAllActiveCampus()).thenReturn(campusList);
assertEquals(2, campusService.listAllActiveCampus().size());
}
But the test result is:
org.opentest4j.AssertionFailedError:
Expected :2
Actual :0
The question is: Should I create a new array with 2 values only? Is there a better way to create better conclusive test?
EDIT
campusService code:
@Override
public List<Campus> getAllCampus() {
return campusRepository.findAll();
}
...
@Override
public List<Campus> listAllActiveCampus() {
return campusRepository.findAllActiveCampus();
}
The repository:
public interface ICampusRepository extends JpaRepository<Campus, Integer> {
@Query(value = "SELECT * FROM catSede WHERE sedeEstatusId = 3", nativeQuery = true)
List<Campus> findAllActiveCampus();
}
EDIT 2
Full test Class:
@SpringBootTest
class CampusServiceImplementationTest {
@Mock
private ICampusRepository campusRepository;
@InjectMocks
private CampusServiceImplementation campusService;
@BeforeEach
void setUp() {
MockitoAnnotations.openMocks(this);
}
@Test
void getAllCampus() {
List<Campus> campusList = new ArrayList<>();
campusList.add(new Campus(1, "Campus Name 1", "ACTIVE"));
campusList.add(new Campus(2, "Campus Name 2", "ACTIVE"));
campusList.add(new Campus(3, "Campus Name 3", "INACTIVE"));
when(campusRepository.findAll()).thenReturn(campusList);
List<Campus> result = campusRepository.findAll();
assertNotNull(result);
assertEquals(3, result.size());
verify(campusRepository, times(1)).findAll();
}
@Test
void listAllActiveCampus() {
List<Campus> campusList = new ArrayList<>();
campusList.add(new Campus(1, "Campus Name 1", "ACTIVE"));
campusList.add(new Campus(2, "Campus Name 2", "ACTIVE"));
campusList.add(new Campus(3, "Campus Name 3", "INACTIVE"));
when(campusRepository.findAllActiveCampus()).thenReturn(campusList);
List<Campus> result = campusRepository.findAllActiveCampus();
assertNotNull(result);
assertEquals(2, result.size());
verify(campusRepository, times(1)).findAllActiveCampus();
}
}
Service class:
@Service
@RequiredArgsConstructor
public class CampusServiceImplementation implements ICampusService {
private final ICampusRepository campusRepository;
@Override
public List<Campus> getAllCampus() {
return campusRepository.findAll();
}
@Override
public List<Campus> listAllActiveCampus() {
return campusRepository.findAllActiveCampus();
}
}
Repository:
public interface ICampusRepository extends JpaRepository<Campus, Integer> {
@Query(value = "SELECT * FROM catSede WHERE sedeEstatusId = 3", nativeQuery = true)
List<Campus> findAllActiveCampus();
}
CodePudding user response:
There is something off: When you write
when(campusRepository.findAllActiveCampus()).thenReturn(campusList);
assertEquals(2, campusService.listAllActiveCampus().size());
and your setUp()
is as shown, then you should get the Error:
org.opentest4j.AssertionFailedError:
Expected :2
Actual :3
because you configured your ´campusRepository´ so that when called with ´findAllActiveCampus()´ it should return ´campusList´ which in turn contains 3 not 2 elements , even if only 2 elements are "ACTIVE".
Remember that the @Query(value = "SELECT * FROM catSede WHERE sedeEstatusId = 3", nativeQuery = true)
is not executed at all in this test, because the repository is just a mock!
CodePudding user response:
There are a few parts of your question:
- Why the stubbing does not work?
This stems from the fact that you re-initialize your mocks:
- @SpringBootTest
- MockitoAnnotations.openMocks
While @Mock fields are re-initialized, the @InjectMocks are not, so the service points to a different repository that the test points to.
- Usage of SpringBootTest
This is used to create all beans from the app context - this is an overkill for the test where you are using only one service and one mocked repository
- Is mocking a correct way to test an SQL query?
Definitely not. Your current test check that the service returns whatever the repository returns, which is a a valid konf of test (and becomes really useful if you have smoe logic in the business layer).
If you want to test SQL query, you have no other option than use a database. Your query is really simple, so you can get away with an in-memory DB, but you'll soon reach a point where SQL dialects matter, and you will be better off if you test against same kind of db that you use in production (launching it in docker is a common practice)