Just wanna ask as I am stuck in the test cases and getting error as "Actually, there were zero interactions with this mock".
I have created an Dao Implementation class which is doing CRUD operation.
public class EmployeeDaoImpl implements EmployeeDao {
#Override
public void saveEmployee(EmployeeDetails employee) {
Session session = HibernateUtil.getSessionFactory().openSession();
Transaction transaction = session.beginTransaction();
session.save(employee);
transaction.commit();
session.close();
}
}
And for this above class I am building the test using Mockito. So for my above saveEmployee method Session, TRansaction I have made it as Mock object and now I need to check session , save method and transaction as well.
So I have written the Mockito code below:
/**
*
*/
package sandeep.test;
import static org.junit.Assert.*;
import javax.transaction.HeuristicMixedException;
import javax.transaction.HeuristicRollbackException;
import javax.transaction.RollbackException;
import javax.transaction.SystemException;
import javax.transaction.Transaction;
import junit.framework.Assert;
import org.hibernate.Session;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.runners.MockitoJUnitRunner;
import sandeep.DAO.EmployeeDao;
import sandeep.DAOImpl.EmployeeDaoImpl;
import sandeep.DAOImpl.HibernateUtil;
import sandeep.pojo.EmployeeDetails;
import static org.mockito.Mockito.*;
/**
* #author sandeep
*
*/
#RunWith(MockitoJUnitRunner.class)
public class EmployeeDaoImplTest {
#Mock
EmployeeDetails edt;
#Mock
Session session ;
#Mock
Transaction transaction;
#InjectMocks
EmployeeDaoImpl edi = new EmployeeDaoImpl();
#Before
public void setUp() throws Exception {
//eimpl = new EmployeeDaoImpl();
//emp= mock(EmployeeDao.class);
}
#After
public void tearDown() throws Exception {
}
#Test
public void testSaveEmployee(){
edi.saveEmployee(getEmployeeDetails());
// But here i am getting the error as zero interactions
verify(session, times(1)).save(EmployeeDetails.class);
}
public EmployeeDetails getEmployeeDetails(){
edt = new EmployeeDetails();
edt.setEname("sandeep");
edt.setId(2);
edt.setEnumber("hoi");
return edt;
}
}
I have debugged the code and the code is passing onto all the breakpoints in my IDE and when I execute this the 3 values it will be added to the database but my test case will fail as there are zero interactions.
The Session mock in your test is not the same object used in EmployeeDaoImpl#saveEmployee
Implement a constructor for EmployeeDaoImpl with a Session argument and use that argument in the saveEmployee() method. This allows your #InjectMocks to work as intended.
#RunWith(MockitoJUnitRunner.class)
public class MockitoTest {
#Mock
Session session;
#InjectMocks
EmployeeDaoImpl edi;
#Test
public void testSaveEmployee(){
edi.saveEmployee();
verify(session, times(1)).save();
}
}
class Session {
void save() {
System.out.println("saving");
}
}
interface EmployeeDao {
void saveEmployee();
}
class EmployeeDaoImpl implements EmployeeDao {
private Session session;
public EmployeeDaoImpl(Session session) {
this.session = session;
}
#Override
public void saveEmployee() {
session.save();
}
}
Related
I am using JUnit5.
I have following scenario:
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockedStatic;
import org.mockito.junit.jupiter.MockitoExtension;
#ExtendWith(MockitoExtension.class)
public class SomeClassTest {
// needs to be mocked but not injected
#Mock
private EntityManager entityManager;
// needs to be mocked and injected
#Mock
private SomeDao someDao;
#InjectMocks
private SomeClass someClass = new someClass(entityManager);
public class SomeClass{
EntityManager entityManager;
public SomeClass(EntityManager entityManager) {
if (entityManager == null) {
throw new NullpointerException("Manager is null");
} else {
this.entityManager = entityManager;
}
The problem is:
mocked EntityManager object is needed to create the class I want to test
must inject SomeDao which is needed in SomeClass
I get a nullpointer because the mocked object appears not to be created when I give it as argument to the constructor
Has anybody an idea how to solve this? I could create a no-arg constructor but that would give me a constructor which I only need for testing which isn't that 'clean'.
You should add your SomeDao someDao as an arg to SomeClass constructor and then you will be able to manipulate it via tests using #Mock
Looking at this answer (https://stackoverflow.com/a/67081911/11431537) Mockito is using 3 ways to inject a mock.
The first one is injecting it in the constructor if there is a constructor which takes the argument.
Therefore, I changed my constructor as #nesmeyana mentioned:
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import javax.persistence.EntityManager;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.when;
#ExtendWith(MockitoExtension.class)
public class SomeClassTest {
#Mock
private EntityManager mockEntityManager;
#Mock
private SomeDao mockSomeDao;
#InjectMocks
private SomeClass someClass;
#Test
public void test() {
when(mockSomeDao.duck()).thenReturn(10);
assertEquals(10, someClass.bla());
}
}
public class SomeClass{
EntityManager entityManager;
SomeDao someDao;
public SomeClass(EntityManager entityManager, SomeDao someDao) {
if (entityManager == null) {
throw new NullpointerException("Manager is null");
} else {
this.entityManager = entityManager;
this.someDao = someDao;
}
public class SomeDao{
int x = 5;
public SomeDao(int x) {
this.x = x;
}
public int duck() {
return x;
}
}
But since I had to change my code to be able to test my classes, I have to rethink my code writing in general!
I and everybody who reads this, should avoid hard dependencies and use CI (dependency injection) to be able to test their code easily.
I am not using any framework just using maven war module and want to test the DAO layer using Juit 4 + Powermockito (first time).
My idea is when I call CustomerDao to test createCustomer. First statement of this method is as below:
Session session = HibernateManager.getInstance().getSessionFactory().openSession();
I want to mock this call so that I can provide the session object which I constructed in the test class using following code:
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.powermock.modules.junit4.PowerMockRunner;
import com.dao.CustomerDao;
#RunWith(PowerMockRunner.class)
public class CustomerDaoTest {
private SessionFactory sessionFactory;
#Mock
CustomerDao customer=new CustomerDao();
#Before
public void setup() {
sessionFactory = createSessionFactory();
}
#Test
public void CustomerCreateAndDeleteTest() throws Exception {
// Want to mock here
int id=customer.createCustomer("Indian Customer", "India", "xyz#pk.com",
"234567890", "AB");
Assert.assertEquals(1, id);
}
private SessionFactory createSessionFactory() {
Configuration configuration = new Configuration().configure("hibernate.cfg.h2.xml");// Using H2 for testing only
sessionFactory = configuration.buildSessionFactory();
return sessionFactory;
}
}
Problem is:
When I run my test class I am getting error:
org.hibernate.internal.util.config.ConfigurationException: Unable to
perform unmarshalling at line number -1 and column -1 in RESOURCE
hibernate.cfg.h2.xml. Message: unexpected element
(uri:"http://www.hibernate.org/xsd/orm/cfg",
local:"hibernate-configuration"). Expected elements are
<{}hibernate-configuration>
But if I remove annotation #RunWith(PowerMockRunner.class)
then I am not getting this error.
How can I mock the method call which is inside the createCustomer() method as below:
Session session = HibernateManager.getInstance().getSessionFactory().openSession();
Please guide me how I can write Unit test case to test the DAO layer which can use a different hibernate.cfg.xml file.
The issue appears to be PowerMocks classloader.
Unable to parse hibernate.cfg.xml
I got PowerMock, JUnit4, and Hibernate to work in JDK11 following the same principal, and adding the following to my Class:
#PowerMockIgnore({"com.sun.org.apache.xerces.*", "javax.xml.*", "org.xml.*", "org.hibernate.*"})
Full class example:
org.hibernate hibernate-core 5.4.2.Final (compile)
junit junit:4.12 (test)
net.bytebuddy byte-buddy 1.9.10 (compile)
org.powermock powermock-module-junit4 2.0.2 (test)
com.h2database h2 1.4.199 (test)
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.core.classloader.annotations.PowerMockIgnore;
import org.powermock.modules.junit4.PowerMockRunner;
#RunWith(PowerMockRunner.class)
#PowerMockIgnore({"com.sun.org.apache.xerces.*", "javax.xml.*", "org.xml.*", "org.hibernate.*"})
public class PowerMockHibernateTest {
private SessionFactory sessionFactory;
public PowerMockHibernateTest() {
}
#Before
public void setUp() {
sessionFactory = createSessionFactory();
}
#After
public void tearDown() {
sessionFactory.close();
}
private Session getNewSession() {
return sessionFactory.openSession();
}
#Test
public void getQuery() {
Session session = getNewSession();
session.createNamedQuery("PostEntity.All", PostEntity.class);
}
private SessionFactory createSessionFactory() {
Configuration configuration = new Configuration().configure("hibernate.cfg.h2.xml");
configuration.setProperty("hibernate.dialect", "org.hibernate.dialect.H2Dialect");
configuration.setProperty("hibernate.connection.driver_class", "org.h2.Driver");
configuration.setProperty("hibernate.connection.url", "jdbc:h2:mem:test");
configuration.setProperty("hibernate.hbm2ddl.auto", "update");
return configuration.buildSessionFactory();
}
}
I have an ItemProcessor which has a #BeforeStep method to access the ExecutionContext:
public class MegaProcessor implements ItemProcessor<String, String> {
private ExecutionContext context;
#BeforeStep
void getExecutionContext(final StepExecution stepExecution) {
this.context = stepExecution.getExecutionContext();
}
#Override
public String process(final String string) throws Exception {
// ...
}
}
The unit test for this class:
#ContextConfiguration(classes = MegaProcessor.class)
#TestExecutionListeners({ DependencyInjectionTestExecutionListener.class, StepScopeTestExecutionListener.class })
#RunWith(SpringRunner.class)
public class MegaProcessorTest {
#Autowired
private MegaProcessor sut;
public StepExecution getStepExecution() {
StepExecution execution = MetaDataInstanceFactory.createStepExecution();
execution.getExecutionContext().put("data", "yeah");
return execution;
}
#Test
public void MegaProcessor() throws Exception {
assertNotNull(sut.process("pew pew"));
}
}
When I debug the test run, context is null and the #BeforeStep method is never called. Why is that and how to achieve that?
Why is that
If you want to use the StepScopeTestExecutionListener, the tested component should be step-scoped (See Javadoc). It's not the case in your example. But this is not the real issue. The real issue is that the method annotated with #BeforeStep will be called before the step in which your processor is registered is executed. In your test case, there is no step running so the method is never called.
how to achieve that?
Since it is a unit test, you can assume the step execution will be passed to your item processor by Spring Batch before running the step and mock/stub it in your unit test. This is how I would unit test the component:
import org.junit.Before;
import org.junit.Test;
import org.springframework.batch.core.StepExecution;
import static org.junit.Assert.assertNotNull;
public class MegaProcessorTest {
private MegaProcessor sut;
#Before
public void setUp() {
StepExecution execution = MetaDataInstanceFactory.createStepExecution();
execution.getExecutionContext().put("data", "yeah");
sut = new MegaProcessor();
sut.getExecutionContext(execution); // I would rename getExecutionContext to setExecutionContext
}
#Test
public void MegaProcessor() throws Exception {
assertNotNull(sut.process("pew pew"));
}
}
The StepScopeTestExecutionListener is handy when you have step-scoped components that use late-binding to get values from the step execution context. For example:
#Bean
#StepScope
public ItemReader<String> itemReader(#Value("#{stepExecutionContext['items']}") String[] items) {
return new ListItemReader<>(Arrays.asList(items));
}
A unit test of this reader would be something like:
import java.util.Arrays;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.batch.core.StepExecution;
import org.springframework.batch.core.configuration.annotation.StepScope;
import org.springframework.batch.item.ItemReader;
import org.springframework.batch.item.support.ListItemReader;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.TestExecutionListeners;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.context.support.DependencyInjectionTestExecutionListener;
#ContextConfiguration(classes = StepScopeExecutionListenerSampleTest.MyApplicationContext.class)
#TestExecutionListeners({ DependencyInjectionTestExecutionListener.class, StepScopeTestExecutionListener.class })
#RunWith(SpringRunner.class)
public class StepScopeExecutionListenerSampleTest {
#Autowired
private ItemReader<String> sut;
public StepExecution getStepExecution() {
StepExecution execution = MetaDataInstanceFactory.createStepExecution();
execution.getExecutionContext().put("items", new String[] {"foo", "bar"});
return execution;
}
#Test
public void testItemReader() throws Exception {
Assert.assertEquals("foo", sut.read());
Assert.assertEquals("bar", sut.read());
Assert.assertNull(sut.read());
}
#Configuration
static class MyApplicationContext {
#Bean
#StepScope
public ItemReader<String> itemReader(#Value("#{stepExecutionContext['items']}") String[] items) {
return new ListItemReader<>(Arrays.asList(items));
}
/*
* Either declare the step scope like the following or annotate the class
* with `#EnableBatchProcessing` and the step scope will be added automatically
*/
#Bean
public static org.springframework.batch.core.scope.StepScope stepScope() {
org.springframework.batch.core.scope.StepScope stepScope = new org.springframework.batch.core.scope.StepScope();
stepScope.setAutoProxy(false);
return stepScope;
}
}
}
Hope this helps.
How to programmatically control transaction boundaries within single #Test method? Spring 4.x documentation has some clues but I think I missing something since the test throws error:
java.lang.IllegalStateException:
Cannot start a new transaction without ending the existing transaction first.
Test
import com.hibernate.query.performance.config.ApplicationConfig;
import com.hibernate.query.performance.config.CachingConfig;
import com.hibernate.query.performance.persistence.model.LanguageEntity;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.TestExecutionListeners;
import org.springframework.test.context.junit4.AbstractTransactionalJUnit4SpringContextTests;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.support.AnnotationConfigContextLoader;
import org.springframework.test.context.transaction.TestTransaction;
import org.springframework.transaction.annotation.Transactional;
import javax.persistence.PersistenceContext;
import java.util.List;
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = { ApplicationConfig.class, CachingConfig.class }, loader = AnnotationConfigContextLoader.class)
#PersistenceContext
#Transactional(transactionManager = "hibernateTransactionManager")
#TestExecutionListeners({})
public class EHCacheTest extends AbstractTransactionalJUnit4SpringContextTests {
private static Logger logger = LoggerFactory.getLogger(EHCacheTest.class);
#BeforeClass
public static void setUpBeforeClass() throws Exception {
logger.info("setUpBeforeClass()");
}
#AfterClass
public static void tearDownAfterClass() throws Exception {
logger.info("tearDownAfterClass()");
}
#Autowired
private SessionFactory sessionFactory;
#Test
public void testTransactionCaching(){
TestTransaction.start();
Session session = sessionFactory.getCurrentSession();
System.out.println(session.get(LanguageEntity.class, 1));
Query query = session.createQuery("from LanguageEntity le where le.languageId < 10").setCacheable(true).setCacheRegion("language");
#SuppressWarnings("unchecked")
List<LanguageEntity> customerEntities = query.list();
System.out.println(customerEntities);
session.getTransaction().commit();
TestTransaction.flagForCommit();
TestTransaction.end();
// Second Transaction
TestTransaction.start();
Session sessionNew = sessionFactory.getCurrentSession();
System.out.println(sessionNew.get(LanguageEntity.class, 1));
Query anotherQuery = sessionNew.createQuery("from LanguageEntity le where le.languageId < 10");
anotherQuery.setCacheable(true).setCacheRegion("language");
#SuppressWarnings("unchecked")
List<LanguageEntity> languagesFromCache = anotherQuery.list();
System.out.println(languagesFromCache);
sessionNew.getTransaction().commit();
TestTransaction.flagForCommit();
TestTransaction.end();
}
}
UPDATE
One more detail:
All occurences session.getTransaction().commit(); must be removed since they interrupt transaction workflow.
TL;DR
In order to avoid this problem, just remove the first line of the test method and use the already available transaction:
#Test
public void testTransactionCaching() {
// Remove this => TestTransaction.start();
// Same as before
}
Detailed Answer
When you annotate your test class with #Transactional or extending the AbstractTransactionalJUnit4SpringContextTests:
// Other annotations
#Transactional(transactionManager = "hibernateTransactionManager")
public class EHCacheTest extends AbstractTransactionalJUnit4SpringContextTests { ... }
Each test method within that class will be run within a transaction. To be more precise, Spring Test Context (By using TransactionalTestExecutionListener) would open a transaction in the beginning of each test method and roll it back after completion of the test.
So, your testTransactionCaching test method:
#Test
public void testTransactionCaching() { ... }
Would have an open transaction in the beginning and you're trying to open another one manually by:
TestTransaction.start();
Hence the error:
Cannot start a new transaction without ending the existing transaction
first.
In order to avoid this problem, just remove the first line of the test method and use that already available transaction. The other TestTransaction.* method calls are OK but just remove the first one.
This test is failing but I don't know why or how to fix it. If I hit a break point and call mockingContext.getBean(Repository.class), it does return my mock object, but for some reason the ProductionCode returned in createProductionCodeWithMock still has the real Repository autowired into it. I can only suspect that I need to do something special/extra to have an effect on autowired beans, but I don't know what it is. Why isn't this test passing, and how can I make it pass?
For what it's worth, I'm well aware of all the answers to this question. I still want to know why this test isn't working. I am using Spring 3.x.
Here's the test:
package mavensnapshot;
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.context.support.GenericApplicationContext;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
public class ProductionCodeTest {
#Test
public void testReplaceRepositoryWithMock() {
Repository mockRepository = mock(Repository.class);
ProductionCode productionCode = createProductionCodeWithMock(mockRepository);
productionCode.doSomething();
verify(mockRepository).save();
}
private ProductionCode createProductionCodeWithMock(Repository mockRepository) {
GenericApplicationContext mockingContext = new GenericApplicationContext();
mockingContext.getBeanFactory().registerSingleton(Repository.class.getName(), mockRepository);
mockingContext.setParent(new ClassPathXmlApplicationContext("/beans.xml"));
return mockingContext.getBean(ProductionCode.class);
}
}
Here's my production code:
package mavensnapshot;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Main {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("/beans.xml");
ProductionCode productionCode = context.getBean(ProductionCode.class);
productionCode.doSomething();
}
}
package mavensnapshot;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
#Service
public class ProductionCode {
#Autowired
private Repository repository;
public void doSomething() {
repository.save();
}
}
package mavensnapshot;
import org.springframework.stereotype.Service;
#Service
public class Repository {
public void save() {
System.out.println("production code");
}
}