Spring JUnit + Mockito + In memory Database (H2) - java

I'm currently using Mockito and In memory Database (H2) in order to test some services and dao.
I've tried to test a method (createRoad) of my service that contains some call of dao method :
#Service(value = "RoadsService")
public class RoadsService implements IRoadsService {
#Autowired
private IRoadsDao roadsDao;
...
#Override
public long createRoad(CreateRoadCriteria criteria) {
String roaCodeToCopy = "";
RoadsCriteria roadsCriteria = new RoadsCriteria();
roadsCriteria.setCe(criteria.getCe());
roadsCriteria.setDeliveryDate(new Date());
List<WebRoadsModel> listRoadsCe = roadsDao
.getRoadsByCEAndDeliveryDate(roadsCriteria);
for (WebRoadsModel wrm : listRoadsCe) {
if (wrm.getRoaCode().endsWith("90")) {
roaCodeToCopy = wrm.getRoaCode();
break;
}
}
criteria.setRoadCode(StringUtils.substring(roaCodeToCopy, 0, 4)
+ criteria.getRoadCode());
// 2. Creation of the new road
long idNewRoad = roadsDao.createNewRoad(criteria);
if (!"".equals(roaCodeToCopy) && listRoadsCe.get(0) != null) {
roaCodeToCopy = listRoadsCe.get(0).getRoaCode();
// 3. Copy dates closed of this trn
RoadsCriteria newRoadCreated = new RoadsCriteria();
newRoadCreated.setCe(criteria.getCe());
newRoadCreated.setRoadId(idNewRoad);
// 4. Paste it for the new road
deliveryCalendarDao.copyClosedDates(roadsDao
.getRoadByCriteria(newRoadCreated).get(0).getRoaCode(),
roaCodeToCopy);
}
return idNewRoad;
}
...
}
I need to mock the method called getRoadsByCEAndDeliveryDate, because the sql query behind that is not managed by the H2 driver (query with "RANK"). Then, I want to use H2 with the other method in this service.
I've tried this :
public class RoadsServiceTest {
#InjectMocks
private RoadsService roadsService;
#Mock
private MockRoadDao roadsDao;
#BeforeClass
public static void setUpClass() throws Exception {
}
#Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
}
#Test
public void createRoad(){
CreateRoadCriteria criteria = new CreateRoadCriteria();
criteria.setRoadCode("AA");
criteria.setRoadName("ANAME");
criteria.setCe("2");
criteria.setDriver(1);
criteria.setVehicle(1);
criteria.setSupplier(1);
List<WebRoadsModel> expected = new ArrayList<WebRoadsModel>();
Mockito.when(roadsDao.getRoadsByCEAndDeliveryDate((RoadsCriteria) Mockito.any())).thenReturn(expected);
Mockito.when(roadsDao.getNextVal(Mockito.anyString())).thenCallRealMethod();
Mockito.when(roadsDao.createNewRoad(criteria)).thenCallRealMethod();
long result = roadsService.createRoad(criteria);
Assert.assertEquals(5, result);
}
}
It is almost good except the assertEquals.
According to my sql file used with my in memory database, i have a sql sequence like this :
CREATE SEQUENCE "SEQ_SITI_ROADS" MINVALUE 1 MAXVALUE 99999 INCREMENT BY 1 START WITH 5 CACHE 20 ;
When I run my test, the result is 0.
It seems that the MockRoadDao is not initialized.
public class MockRoadDao extends RoadsDao {
public MockRoadDao() throws DatabaseUnitException, SQLException, MalformedURLException {
IDataSet dataSet = new FlatXmlDataSetBuilder().build(new File("./src/test/resources/dataset.xml"));
DataSource dataSource = TestUtils.dataSource();
IDatabaseConnection dbConn = new DatabaseDataSourceConnection(dataSource);
DatabaseOperation.CLEAN_INSERT.execute(dbConn, dataSet);
User user = new User();
user.setLangCountry("ENFR");
BackendContextHolder.setBackendIdentifier(new BackendIdentifierImpl(user));
final NamedParameterJdbcTemplate jdbcTemplate = new NamedParameterJdbcTemplate(dataSource);
setJdbcTemplate(jdbcTemplate);
}
}
public class TestUtils {
private static final Logger LOG = LoggerFactory.getLogger(TestUtils.class);
public static DataSource datasource;
/**
* #return
*/
public static DataSource dataSource() {
if (datasource == null) {
EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder();
EmbeddedDatabase db = builder.setType(EmbeddedDatabaseType.H2).addScript("classpath:/siti-create.sql").build();
datasource = db;
}
return datasource;
}
...
}
Could you please help me :)
Thank you in advance
Edit :
#Baski : When I remove #Mock and use ReflectionUtils instead, the constructor of MockRoadDAO is called. But, when I run the test, the method roadsDao.getRoadsByCEAndDeliveryDate() is not mocked with Mockito, the method is really called and unfortunately the SQL query is not managed by the H2 driver.
public class RoadsServiceTest {
#InjectMocks
private RoadsService roadsService;
private MockRoadDao roadsDao;
#BeforeClass
public static void setUpClass() throws Exception {
}
#Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
roadsDao = new MockRoadDao();
ReflectionTestUtils.setField(roadsService, "roadsDao", roadsDao);
}
#Test
public void createRoad(){
CreateRoadCriteria criteria = new CreateRoadCriteria();
criteria.setRoadCode("AA");
criteria.setRoadName("ANAME");
criteria.setCe("2");
criteria.setDriver(1);
criteria.setVehicle(1);
criteria.setSupplier(1);
List<WebRoadsModel> expected = new ArrayList<WebRoadsModel>();
Mockito.when(roadsDao.getRoadsByCEAndDeliveryDate((RoadsCriteria) Mockito.any())).thenReturn(expected);
Mockito.when(roadsDao.getNextVal(Mockito.anyString())).thenCallRealMethod();
Mockito.when(roadsDao.createNewRoad(criteria)).thenCallRealMethod();
long result = roadsService.createRoad(criteria);
Assert.assertEquals(5, result);
}
}

Related

How to write Junit test cases for EntityManger createNativeQuery with String and class as parameters

#Repository
public class DesignatorDaoImpl extends GenericDaoImpl implements DesignatorDao {
#Autowired
EntityManager em;
public List<Designator> getDesignators(DesignatorRequestDTO dto) throws Exception {
List<Designator> designatorsList = new ArrayList<>();
int start = dto.getStart();
String queryString ="select * from ( SELECT * FROM TAB.DESIGNATOR WHERE ACTIVE_IND ='A' ORDER BY LAST_EDITED_DATE DESC ) OFFSET "+ start +" ROWS FETCH NEXT "+dto.getLimit()+" ROWS ONLY";
Query query = em.createNativeQuery(queryString,Designator.class);
designatorsList = query.getResultList();
return designatorsList;
}
}
I have the above class to get records from DB. I wrote JUnit test for this above class as
#Transactional
#Rollback(true)
public class DesignatorDaoImplTest {
#Mock
EntityManager entityManagerMock;
#Mock
TypedQuery<Designator> getQuery;
#InjectMocks
DesignatorDaoImpl designatorDaoImpl;
DesignatorRequestDTO dto = new DesignatorRequestDTO();
List<Designator> designatorEntityList = new ArrayList<>();
#Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
dto.setLimit(4);
dto.setStart(1);
Designator entity = new Designator();
entity.setId("dgbkk");
designatorEntityList.add(entity);
}
#Test
public void saveDesignatorTest() throws Exception {
Mockito.when(entityManagerMock.createNamedQuery(ArgumentMatchers.anyString(), ArgumentMatchers.eq(Designator.class))).thenReturn(getQuery);
Mockito.when(getQuery.getResultList()).thenReturn(designatorEntityList);
assertNotNull(designatorDaoImpl.saveDesignators(dto));
}
}
I have problem mocking and at this em.createNativeQuery(queryString,Designator.class) in dao class I am getting null. How can I properly mock the em.createNativeQuery in test class?
According to the documentation, if you are using argument matchers, all arguments have to be provided by matchers. Hence, try using ArgumentMatchers.eq() (reference documentation) to check for Designator.class equality:
#Mock
TypedQuery<Designator> getQuery;
#Test
public void saveDesignatorTest() throws Exception {
Mockito.when(entityManagerMock.createNamedQuery(ArgumentMatchers.anyString(), ArgumentMatchers.eq(Designator.class))).thenReturn(getQuery);
Mockito.when(getQuery.getResultList()).thenReturn(designatorEntityList);
assertNotNull(designatorDaoImpl.getDesignators(dto));
}
Avoid using property injection and use constructor injection instead:
#Repository
public class DesignatorDaoImpl extends GenericDaoImpl implements DesignatorDao {
private EntityManager em;
public DesignatorDaoImpl(EntityManager em) {
super();
this.em = em;
}
public List<Designator> getDesignators(DesignatorRequestDTO dto) throws Exception {
List<Designator> designatorsList = new ArrayList<>();
int start = dto.getStart();
String queryString ="select * from ( SELECT * FROM TAB.DESIGNATOR WHERE ACTIVE_IND ='A' ORDER BY LAST_EDITED_DATE DESC ) OFFSET "+ start +" ROWS FETCH NEXT "+dto.getLimit()+" ROWS ONLY";
Query query = em.createNativeQuery(queryString,Designator.class);
designatorsList = query.getResultList();
return designatorsList;
}
}
Then you need to drop #InjectMocks because you are injecting them before being initialized and create the instance of DesignatorDaoImpl to test in the #Before method:
#Transactional
#Rollback(true)
public class DesignatorDaoImplTest {
#Mock
EntityManager entityManagerMock;
#Mock
TypedQuery<Designator> getQuery;
DesignatorDaoImpl designatorDaoImpl;
DesignatorRequestDTO dto = new DesignatorRequestDTO();
List<Designator> designatorEntityList = new ArrayList<>();
#Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
dto.setLimit(4);
dto.setStart(1);
Designator entity = new Designator();
entity.setId("dgbkk");
designatorEntityList.add(entity);
designatorDaoImpl = new DesignatorDaoImpl(entityManagerMock);
}
#Test
public void saveDesignatorTest() throws Exception {
Mockito.when(entityManagerMock.createNamedQuery(ArgumentMatchers.anyString(), ArgumentMatchers.eq(Designator.class))).thenReturn(getQuery);
Mockito.when(getQuery.getResultList()).thenReturn(designatorEntityList);
assertNotNull(designatorDaoImpl.saveDesignators(dto));
}
}
If you can't change DesignatorDaoImpl then use #RunWith(MockitoJUnitRunner.class) instead of MockitoAnnotations.initMocks(this);as follows:
#Transactional
#Rollback(true)
#RunWith(MockitoJUnitRunner.class)
public class DesignatorDaoImplTest {
#Mock
EntityManager entityManagerMock;
#Mock
TypedQuery<Designator> getQuery;
#InjectMocks
DesignatorDaoImpl designatorDaoImpl;
DesignatorRequestDTO dto = new DesignatorRequestDTO();
List<Designator> designatorEntityList = new ArrayList<>();
#Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
dto.setLimit(4);
dto.setStart(1);
Designator entity = new Designator();
entity.setId("dgbkk");
designatorEntityList.add(entity);
}
#Test
public void saveDesignatorTest() throws Exception {
Mockito.when(entityManagerMock.createNamedQuery(ArgumentMatchers.anyString(), ArgumentMatchers.eq(Designator.class))).thenReturn(getQuery);
Mockito.when(getQuery.getResultList()).thenReturn(designatorEntityList);
assertNotNull(designatorDaoImpl.saveDesignators(dto));
}
}

Null Pointer exception passed by test method

Method that needs to be tested - located in AnalyticsServiceImpl.java class
public void trackSplashState(MeasurementViewEnum measurementViewEnum) {
HashMap<String, Object> data = createCommonData(measurementViewEnum);
MeasureServiceImpl.StartStatus status = mMeasureService.getLaunchStatus();
switch (status) {
case INSTALL:
data.put(APP_EVENT_INSTALL, INSTALL);
break;
case LAUNCH:
data.put(APP_EVENT_LAUNCH, LAUNCH);
break;
case UPDATE:
data.put(APP_EVENT_UPDATE, UPDATE);
break;
}
trackState(measurementViewEnum, data);
}
Test class
#Config(constants = BuildConfig.class, sdk = TestConfig.SDK)
#RunWith(RobolectricTestRunner.class)
public class AnalyticsServiceImplTest {
#Module(includes = TestAppModule.class, injects = AnalyticsServiceImplTest.class, overrides = true)
static class TestModule {
}
#Inject
AnalyticsServiceImpl analyticsServiceImpl;
#Inject
MeasureServiceImpl measureService;
#Inject
Context mContext;
#Inject
LoginService mLoginService;
#Captor
ArgumentCaptor<HashMap<String, Object>> data;
#Captor
ArgumentCaptor<String[]> varargs;
private ArgumentCaptor<MeasurementViewEnum> enumArgumentCaptor;
#Before
public void setUp() throws Exception {
Services.initialize(new AnalyticsServiceImplTest.TestModule()).inject(this);
enumArgumentCaptor = ArgumentCaptor.forClass(MeasurementViewEnum.class);
}
#After
public void tearDown() throws Exception {
}
#Test
public void trackSplashState_shouldReturnInstall_whenLaunchStatusEqualsINSTALL() throws Exception {
analyticsServiceImpl = mock(AnalyticsServiceImpl.class);
MeasureServiceMock measureServiceMock = new MeasureServiceMock();
measureServiceMock.setStatus(MeasureServiceImpl.StartStatus.INSTALL);
analyticsServiceImpl.mMeasureService = measureServiceMock;
analyticsServiceImpl.trackSplashState(MeasurementViewEnum.SPLASH);
verify(analyticsServiceImpl, times(1)).trackState(enumArgumentCaptor.capture(), data.capture());
}
}
when I run this test case I got null pointer exception at the last line. I'm a bit new to unit testing. Can you please explain what is the mistake that I have done in this code?
1) You are mocking the SUT which simply wont work:
analyticsServiceImpl = mock(AnalyticsServiceImpl.class);
You will be verifying its trackState method so you need to Spy on it:
analyticsServiceImpl = spy(new AnalyticsServiceImpl());
2) You are capturing the inputs but you are not asserting them in any way. I guess you missed that:
verify(analyticsServiceImpl, times(1)).trackState(enumArgumentCaptor.capture(), data.capture());
Map<String, Object> dataCaptured = data.getValue();
MeasurementViewEnum enumCapture = enumArgumentCaptor.getValue();
// assert these values
UPDATE:
#Before
public void setUp() throws Exception {
MockitoAnnotation.initMocks(this);
}

Unable to invoke method annotated with #PostConstruct when mocked using Mockito

I am trying to write unit tests for Repository layer classes with Junit and Mockito.
I have mocked the base class that supplies NamedParameterJdbcOperations and tried to inject into the repo class.
In the repo class, we are loading sql queries from files on classpath. This is done in a method that is annotated with #PostConstruct.
When trying to test a method of the repo, it is not able to find or load the query and thus throwing NullPointerException.
Need help / suggestion on how to deal with such scenario.
PS: I am not allowed to change the repo class implementation.
Attaching the code of repo and test class for reference.
RepositoryImpl.java
#Repository
public class RepositoryImpl extends AppJdbcImpl implements
Repository {
private static final StudentMapper STUDENT_ROW_MAPPER = new StudentMapper();
private static final CourseMapper COURSE_ROW_MAPPER = new CourseMapper();
#Value("classpath:sql/sql1.sql")
private Resource sql1;
private String query1;
#Value("classpath:sql/sql2.sql")
private Resource sql2;
private String query2;
public RepositoryImpl() { }
public RepositoryImpl(NamedParameterJdbcOperations jdbc) {
super(jdbc);
}
#PostConstruct
public void setUp() {
query1 = loadSql(sql1);
query2 = loadSql(sql2);
}
public Iterable<Course> findCoursesByStudentId(int studentId) throws
DataAccessException {
try {
return jdbc().queryForObject(query1,
ImmutableMap.of("studentId", studentId),
COURSE_ROW_MAPPER);
} catch (EmptyResultDataAccessException emptyResult) {
return null;
} catch (DataAccessException e) {
// Need to create exception classes and throw specific exceptions
throw e;
}
}
public Iterable<Student> findStudentsByCourseId(int courseId) throws DataAccessException {
try {
return jdbc().query(query2,
ImmutableMap.of("courseId", courseId),
STUDENT_ROW_MAPPER);
} catch (DataAccessException e) {
// Need to create exception classes and throw specific exceptions
throw e;
}
}
private String loadSql(Resource resource) {
try {
return CharStreams.toString(new InputStreamReader(resource.getInputStream()));
} catch (IOException e) {
return null;
}
}
}
RespositoryImplTest.java
#RunWith(MockitoJUnitRunner.class)
public class RepositoryImplTest {
#Mock
private NamedParameterJdbcOperations jdbc;
#Mock
private ResultSet resultSet;
#Mock
private StudentMapper studentMapper;
#Mock
private CourseMapper CourseMapper;
#InjectMocks
private RepositoryImpl repository;
private Student student1;
private Student student2;
private Course course1;
private Course course2;
#Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
course1 = new Course(1, "Karate");
course2 = new Course(2, "Riding");
course8 = new Course(8, "Swimming");
List<Course> courseList = Arrays.asList(course1, course2, course8);
student1 = new Student(1, "Chuck", "Norris", 27, new Arrays.asList(course1, course2));
student2 = new Student(2, "Bruce", "Lee", 54, new Arrays.asList(course1, course8));
List<Student> studentList = Arrays.asList(student1, student2);
when(jdbc.queryForObject(Matchers.anyString(), anyMap(),
isA(StudentMapper.class)))
.thenAnswer(new Answer() {
#Override
public Object answer(InvocationOnMock invocationOnMock) throws Throwable {
Object[] args = invocationOnMock.getArguments();
int queryParam = Integer.parseInt(args[0].toString());
Iterable<Credentials> result = studentList.stream()
.filter(d -> d.getId() == queryParam)
.collect(Collectors.toList());
return result;
}
});
}
#Test
public void findCoursesByStudentId() {
Iterable<Course> result = repository.findCoursesByStudentId(1);
assertNotNull(result);
}
}
In repo class, exception is thrown as query1 is null.
Need help to properly solving the issue.
Thanks, Baru
#RunWith(MockitoJUnitRunner.class)
you start test with mockito starter, not spring starter. It's mean that spring not provided you beans. Mockito starter nothing know about PostConstruct annotation.
You may call PostConstruct method youself in sturUp junit method or in test method.

Testing persistence methods - JUnit

I am writing unit tests for my project, but facing some difficulties when calling methods, which work with database. Currently I want to check a method that gets the list of publications that are of users interest, but I am getting NullPointerException:
public class TestPubManager {
private PubManager pFunc;
#Before
public void initialize() {
EntityManager manager = PersistenceManager.INSTANCE.getEntityManager();
em.getTransaction().begin();
PubManager pManager = new PubManager(manager);
}
#Test
public void testGetInterestPubs() {
int res = pManager.getInterestPubs(2).size();
assertEquals(20, res);
}
}
NullPointerException is on the line with int res = pManager.getInterestPubs(2).size();. What am I doing wrong way?
I have found a solution. So the issue was in the constructor - it was not initializing in #Before annotation, but when I put it inside the test, everything worked out fine.
public class TestPubManager {
private PubManager pFunc;
EntityManager manager = PersistenceManager.INSTANCE.getEntityManager();
#Before
public void initialize() {
em.getTransaction().begin();
}
#Test
public void testGetInterestPubs() {
PubManager pManager = new PubManager(manager);
int res = pManager.getInterestPubs(2).size();
assertEquals(20, res);
}
}

Mongodb integration testing. Test data is not created

I am trying to test my mongodb dao using embedded mongodb- but the test data is not being created.
By contrast, if I use the same way to creating objects in real db then it works OK.
This is my config:
public class UnmappableDataDAOTest
{
private static final String LOCALHOST = "127.0.0.1";
private static final String DB_NAME = "itest";
private static final int MONGO_TEST_PORT = 27028;
private static final String CONTRACT_COLLECTION = "ContractAnswers";
private UnmappableDataDAO dao;
private static MongodProcess mongoProcess;
private static Mongo mongo;
private MongoTemplate template;
#BeforeClass
public static void initializeDB() throws IOException
{
RuntimeConfig config = new RuntimeConfig();
config.setExecutableNaming(new UserTempNaming());
MongodStarter starter = MongodStarter.getInstance(config);
MongodExecutable mongoExecutable = starter.prepare(new MongodConfig(Version.V2_2_0, MONGO_TEST_PORT, false));
mongoProcess = mongoExecutable.start();
mongo = new Mongo(LOCALHOST, MONGO_TEST_PORT);
mongo.getDB(DB_NAME);
}
#AfterClass
public static void shutdownDB() throws InterruptedException {
mongo.close();
mongoProcess.stop();
}
#Before
public void setUp() throws Exception {
dao = new UnmappableDataDAO();
template = new MongoTemplate(mongo, DB_NAME);
dao.setMongoOperations(template);
}
#After
public void tearDown() throws Exception
{
template.dropCollection(ContractAnswers.class);
}
#Test
public void testCreate()
{
// Setup Test Data
List<ContractAnswers> contractAnswersList = new ArrayList<>();
ContractAnswers first = new ContractAnswers();
first.setContractId(1L);
first.setTemplateName("firstTemplate");
first.setId("1");
contractAnswersList.add(first);
ContractAnswers second = new ContractAnswers();
second.setContractId(2L);
second.setTemplateName("secondTemplate");
second.setId("2");
contractAnswersList.add(second);
for (ContractAnswers contractAnswers : contractAnswersList)
{
template.save(contractAnswers, CONTRACT_COLLECTION);
}
ContractAnswers third = new ContractAnswers();
third.setContractId(3L);
third.setTemplateName("thirdTemplate");
third.setId("3");
dao.create(third);
List<ContractAnswers> list = template.findAll(ContractAnswers.class);
}
}
The result of findAll() method is null. That means, that data has not been created.
When I use this way of creation: template.save(contractAnswers, CONTRACT_COLLECTION);, test data is created, but I need the way with CONTRACT_COLLECTION as a parameter. All methods in my dao depend on it.
It is strange, but this is how my create method looks like and it works OK:
public void createOrUpdate(ContractAnswers contractAnswers)
{
this.mongoOperations.save(contractAnswers, CONTRACT_COLLECTION);
}
The same code works ok in real database, but not work in test.
Thank you.

Categories