Hot questions for Using Mockito in jdbc
Question:
I have to write some unit tests but I have problem with mocking ResultSet
and jdbc Connection
.
I have this method:
@Test public void test3() throws SQLException, IOException { Connection jdbcConnection = Mockito.mock(Connection.class); ResultSet resultSet = Mockito.mock(ResultSet.class); Mockito.when(resultSet.next()).thenReturn(true).thenReturn(true).thenReturn(true).thenReturn(false); Mockito.when(resultSet.getString(1)).thenReturn("table_r3").thenReturn("table_r1").thenReturn("table_r2"); Mockito.when(jdbcConnection .createStatement() .executeQuery("SELECT name FROM tables")) .thenReturn(resultSet); //when List<String> nameOfTablesList = null; try { nameOfTablesList = Helper.getTablesName(jdbcConnection); } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } //then Assert.assertEquals(nameOfTablesList.size(), 3); }
And error is showing in line executeQuery("SELECT name FROM tables")
and it sounds like this:
java.lang.NullPointerException HelperTest.test3(HelperTest.java:71)
Any ideas whats going wrong?
Answer:
You need to create an expectation on jdbcConnection.createStatement()
.
By default, I believe a null
is returned.
Should read something like:
ResultSet resultSet = Mockito.mock(ResultSet.class); Mockito.when(resultSet.next()).thenReturn(true).thenReturn(true).thenReturn(true).thenReturn(false); Mockito.when(resultSet.getString(1)).thenReturn("table_r3").thenReturn("table_r1").thenReturn("table_r2"); Statement statement = Mockito.mock(Statement.class); Mockito.when(statement.executeQuery("SELECT name FROM tables")).thenReturn(resultSet); Connection jdbcConnection = Mockito.mock(Connection.class); Mockito.when(jdbcConnection.createStatement()).thenReturn(statement);
Question:
I have a compile problem which is strange. I am not able to fix this. The same peice of code works fine in another project
org.mockito.Mockito.when(jdbcTemplate.query(org.mockito.Matchers.anyString(), org.mockito.Matchers.any(BeanPropertyRowMapper.class))).thenReturn(SOMELIST);
I am getting error as
The method query(String, ResultSetExtractor<T>) in the type JdbcTemplate is not applicable for the arguments (String, BeanPropertyRowMapper)
But When I do this, I do not get any error. But I am not expecting this.
BeanPropertyRowMapper<MyClass> mapper = new BeanPropertyRowMapper<MyClass>(MyClass.class); org.mockito.Mockito.when(jdbcTemplate.query(org.mockito.Matchers.anyString(), mapper)).thenReturn(SOMELIST);
I am not sure if this is an Eclipse problem. Appreciate your help on this.
Answer:
Since BeanPropertyRowMapper<T>
is a generic interface, you should invoke any()
like this:
Mockito.when(jdbcTemplate.query(Matchers.anyString(), Matchers.<BeanPropertyRowMapper<MyClass>>any())).thenReturn(SOMELIST);
Question:
I need to create test for this code.
@Autowired JdbcTemplate jdbcTemplate; public List<Row> getData(int id) { // Preconditions here SimpleJdbcCall getCall = new SimpleJdbcCall(jdbcTemplate) .withSchemaName(SCHEMA) .withProcedureName(SP) .declareParameters( // ... ) .returningResultSet("result", (RowMapper<QuestionAnswerRow>) (rs, rowNum) -> .....); MapSqlParameterSource params = new MapSqlParameterSource(); params.addValue("id", id); // other parameters here Map queryRes = getCall.execute(params); List<row> res = (List<row>) queryRes.get("result"); return res; }
Could you show me how can I mock here getCall.execute(params)
response with Mockito?
Answer:
Your problem here is, that you create the whole getCall
object inside your method, which makes it pretty much impossible to somehow inject a mock into that process.
There are a few possibilities here:
a) You can mock your jdbcTemplate
and then try to get that to work by mocking all calls that getCall
will make to the jdbcTemplate
. Since the jdbcTemplate
will probably do all the actual db work, this can work, but honestly, it's probably not worth the effort (since it's absolutely non-trivial).
b) You can switch the whole test to an integration-test, letting it run against an in-memory db, for example. Of course, there are many arguments against using an integration test as a substitute for an unit test, so probably this isn't the best way to go, either. It's possible, though, and using the Spring test utils and annotations it can be pretty simple.
c) This leaves us with a bit of work, which in this case means refactoring:
Since your problem is that you create the SimpleJdbcCall internally, one solution would be to to extract that part, for example, into a factory. This simplified example shows that:
@Component class SimpleJdbcCallFactory { public SimpleJdbcCall create(JdbcTemplate template) { return new SimpleJdbcCall(template); } }
Now you can add an @Autowired dependency to your class and then mock that depencency in your unit test...
@RunWith(MockitoJUnitRunner.class) public class YourTestClassHere { @Mock private SimpleJdbcCallFactory simpleJdbcCallFactory; @InjectMocks private YourClassHere classToTest; @Test public void test() { SimpleJdbcCall mockedCall = Mockito.mock(SimpleJdbcCall.class); Mockito.when( simpleJdbcCallFactory.create(Mockito.any())).thenReturn(mockedCall); Mockito.when( mockedCall ).withSchemaName(Mockito.anyString()).thenReturn(mockedCall); // etc. unfortunately needed for fluent apis (unless they added those in mockito) Mockito.when( mockedCall.execute(Mockito.any()).thenReturn( ... ); classToTest.getData(123); } }
Question:
I am using Spring boot and Mockito for testing. I have been able to write test cases for Service layer and they re working fine. But, the test cases for DAO layer do not. The jdbcTemplate
object that is mocked and autowired gives null
pointer when executing the test case. Below are the details:
My DAOTest
class:
@RunWith(SpringRunner.class) @SpringBootTest(classes = EcommerceApplication.class) public classEcommerceDaoTest { @InjectMocks private IEcommerceDao ecommerceDao = new EcommerceDaoImpl(); @Mock @Autowired private JdbcTemplate as400JdbcTemplate; @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); } @Test public void checkOrderExistsTest() throws EcommerceException{ Mockito.when(as400JdbcTemplate.queryForObject(queryForOrder,new Object[] {"1000"}, int.class)).thenReturn(1); boolean exists = ecommerceDao.checkOrderExists("1000"); assertTrue(exists); } }
EcommerceDAOImpl.java:
@Override public boolean checkOrderExists(String orderNo)throws EcommerceException{ boolean doesExist = false; int count = 0; try{ count= as400JdbcTemplate.queryForObject(queryForOrder, new Object[]{orderNo}, int.class); if(count >0){ doesExist = true; } } catch(Exception e){ } return doesExist; }
AS400Config.java:
@Bean @Autowired public JdbcTemplate as400JdbcTemplate(@Qualifier("as400DataSource")DataSource dataSource) { return new JdbcTemplate(dataSource); }
ECommerceApplication.java
@SpringBootApplication(exclude = { DataSourceAutoConfiguration.class, HibernateJpaAutoConfiguration.class, DataSourceTransactionManagerAutoConfiguration.class }) @EnableTransactionManagement @Import(As400Configuration.class) public class EcommerceApplication { public static void main(String[] args) { SpringApplication.run(EcommerceApplication.class, args); } }
When I am running the test case, I am getting NullPointerException
for as400JdbcTemplate
. The functionality works fine as is. Its just the test cases for DAO layer that fail because of the inability of the jdbcTemplate
to get mocked/autowired.
Please let me know where I am going wrong.
Answer:
You don't need to use
@Mock
and@Autowired
at the same time. Use only@Mock
:@Mock private JdbcTemplate as400JdbcTemplate;
Use instead of
@RunWith(SpringRunner.class)
-->@RunWith(MockitoJUnitRunner.class)
Also to inject mock into DAO you can use ReflectionTestUtils from spring test.
public static void setField(Class targetClass, String name, Object value)
@Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); ReflectionTestUtils.setField(ecommerceDao ,"as400JdbcTemplate" , as400JdbcTemplate); } @Mock private JdbcTemplate as400JdbcTemplate;
Question:
I am trying to use PowerMockito
to mock by DBUtil. Unlike typical testcase, I don't want to mock the db calls completely. Whenever Dbutil.getConnection() is called. I want to return the connection object to my local Database.
The simple jdbc connection code below is not working when i call from @BeforeClass
method. But it works when I call from the java class.
public static Connection getConnection() throws Exception { System.out.println("-------- Connecting to " + Constants.CONNECTION_STR + " ------"); try { Class.forName(Constants.ORACLE_DRIVER_NAME); } catch (ClassNotFoundException e) { throw new Exception("JDBC Driver not found... " + e); } catch (Exception e) { // TODO: handle exception System.out.println("getConnection :: exp :: "+ e); } System.out.println("Oracle JDBC Driver Registered Sucessfully!"); Connection connection = null; try { connection = DriverManager.getConnection(Constants.CONNECTION_STR, Constants.USERNAME, Constants.PASSWORD); } catch (SQLException e) { throw new Exception("Connection Failed!",e); } if (connection != null) { System.out.println("Connected to Database Sucessfully, take control your database now!"); return connection; } System.out.println("Failed to make connection!"); return null; }
My Testclass
@RunWith (PowerMockRunner.class) @PrepareForTest(DbUtil.class) public class MyUtilTest { @Mock private DbUtil dbUtil; @InjectMocks private MyUtil myUtil; private static Connection myDBConn; @BeforeClass public static void beforeClass() throws Exception { myDBConn = OracleJDBCConnetion.getConnection(); // This always throws invalid username/password exception. } @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); } @Test public void testIsAdminUser() throws Throwable{ PowerMockito.mockStatic(DbUtil.class); PowerMockito.when(DbUtil.getConnection()).thenReturn(myDBConn); String accId= "TH123" ; boolean isAdmin = MyUtil.isAdminUser(cloudAccGuid); System.out.println("isAdmin : " + isAdmin); //then PowerMockito.verifyStatic(Mockito.times(1)); DbUtil.getConnection(); assertTrue(isAdmin); //Finally I am closing my connection. if(myDBConn!=null && !myDBConn.isClosed()) OracleJDBCConnetion.closeConnection(myDBConn); } }
The beforeClass method always throws below expection.
Connection Failed! java.sql.SQLException: ORA-01017: invalid username/password; logon denied
But the same code works, when i try from normal Java class.
Can anyone help in understanding whats wrong here?
I am using ojdbc6.jar and powermokito-1.5.6 and my Oracle database version is 11.2.0.4.0
Thanks.
Edit : I found that @PrepareForTest annotation is causing the error. without the annotation connection is successful but mock does not work. can anyone help me in understanding what is happening? I am very new to these mocking stuff.
Answer:
The problem with @PrepareForTest annotation is, it recursively creates stubs for all dependent classes. Since DBUtil class uses java.sql.Connection class , a stub is created for Connection class also.
So, When i try to create connection, it refers to stub class and throws expection.
Add @PowerMockIgnore annotation to the class,to avoid it. @PowerMockIgnore annotation tells the powermock not to create for the classes that falls under the given package.
@RunWith (PowerMockRunner.class) @PrepareForTest({DbUtil.class}) @PowerMockIgnore({"java.sql.*"}) public class MyUtilTest { ... }
This worked for me.
Question:
Please help me to mock below code .Not able to mock getDataSource() which is calling upon JdbcTemplate object.
@Override public List<AttributeThresholdRange> getThresholdsRangeForXHS(QueryThresholdsRequest queryThresholdsRequest) { ArrayOfString attributeGroupIds = queryThresholdsRequest.getAttributeGroupIds(); Map<String, Object> queryParams = new HashMap<>(); queryParams.put("groupids", attributeGroupIds.getStrings()); return new NamedParameterJdbcTemplate(admDatabaseConnector.getJdbcTemplate().getDataSource()) .query(DBQueryConstants.ADM_QUERY_GET_THRESHOLDS_RANGE_FOR_XHS, queryParams, new ResultSetExtractor<List<AttributeThresholdRange>>() { @Override public List<AttributeThresholdRange> extractData(ResultSet resultSet) throws SQLException,DataAccessException { return null; } }); }
Answer:
what´s the Mock framework are you using?
If you are using Mockito just Mock the jdbcTemplate
and put this method in the when()
clause.
when(admDatabaseConnector.getJdbcTemplate().getDataSource()) .query(anyObject(), anyObject(), anyObject())).thenReturn("Your return queryobject");
You must declare the admDatabaseConnector
in the Mock.
Question:
My question is similar to this SO question
I have two JdbcTemplate.queryForObject(..,...,...,)
calls in service like below,
depositPostedAmt = jdbcTemplate.queryForObject(Constants.FETCH_DEPOSIT_POSTED_AMT, BigDecimal.class,new Object[] { remitBean.getDepositId() });
and
claimPostedAmt =jdbcTemplate.queryForObject(Constants.FETCH_CLAIM_POSTED_AMOUNT,BigDecimal.class, new Object[] { claim.getClaimId(), remitBean.getContractNum() });
Third argument, new Object[]
is different among those two calls and actual sql String differs.
So I am trying to use to different mockings to return two different objects in both scenario as shown below ,
when(jdbcTemplate.queryForObject(eq(Constants.FETCH_DEPOSIT_POSTED_AMT), eq(BigDecimal.class), anyObject())).thenReturn(depositPostedAmt); when(jdbcTemplate.queryForObject(eq(Constants.FETCH_CLAIM_POSTED_AMOUNT), eq(BigDecimal.class), anyObject())).thenReturn(claimPostedAmt);
i.e. I wish to receive two different BigDecimal
on two different queries.
I receive depositPostedAmt
as expected but claimPostedAmt
is always null even though I have initialized it in @Before method same as depositPostedAmt
so I am guessing that my when
matcher doesn't found any match. I have tried various syntax for third argument matching like any(Object[].class)
and anyRef(objectArray)
etc but second time, I always get NULL.
I am not sure as what I am missing as there are no errors. I am using JUnit along with Mockito 1.9.5.
Here is sample code - everything works OK except that claimPostedAmt
remains null in called service.
@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes = TestConfig.class, loader = AnnotationConfigContextLoader.class) public class RCMatchDaoImplTest{ @Autowired private RCMatchDaoImpl service; @Autowired private JdbcTemplate jdbcTemplate; @Autowired private Logger logger; private RemitBean remitBean; private List<RemitBean> remitBeanList; private BigDecimal depositPostedAmt,claimPostedAmt,remitAmount; private ClaimVO claim; private List<ClaimVO> claims; @Before public void setUp() throws NoSuchFieldException, SecurityException, Exception{ /* Set dependencies*/ service.setJdbcTemplate(jdbcTemplate); setFinalStatic(RCMatchDaoImpl.class.getDeclaredField("logger"),logger); remitBean = new RemitBean(); remitBeanList=new ArrayList<>(); claim= new ClaimVO(); claims= new ArrayList<>(); remitBeanList.add(remitBean); depositPostedAmt=new BigDecimal(-10); claimPostedAmt = new BigDecimal(-10); remitAmount=new BigDecimal(20); claims.add(claim); } private static void setFinalStatic(Field field, Object newValue) throws Exception{ field.setAccessible(true); Field modifiersField = Field.class.getDeclaredField("modifiers"); modifiersField.setAccessible(true); modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL); field.set(null, newValue); } @Test public void testLucenePost_refund_success() throws SQLException{ /* Set Data */ remitBean.setRemitType("R"); remitBean.setRemitAmt(remitAmount); remitBean.setDepositId(6866418); remitBean.setClaims(claims); depositPostedAmt=depositPostedAmt.add(new BigDecimal(20)); claimPostedAmt=claimPostedAmt.add(new BigDecimal(10)); claim.setClaimId(6866418); claim.setContractNum("100"); Object[] depositParams = new Object[] { 6866418 }; Object[] claimParams = new Object[] { 6866418,"100" }; /* Record Invocations*/ when(jdbcTemplate.queryForObject(eq(Constants.FETCH_DEPOSIT_POSTED_AMT), eq(BigDecimal.class), anyObject())).thenReturn(depositPostedAmt); when(jdbcTemplate.queryForObject(eq(Constants.FETCH_CLAIM_POSTED_AMOUNT), eq(BigDecimal.class), anyObject())).thenReturn(claimPostedAmt); doNothing().when(logger).error(anyString()); /* Play the Service */ service.lucenePost(remitBeanList); /* Verify Results */ /* reset data to original value as in SetUp method*/ }
Just for sake of completeness, here is my context class too,
import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.slf4j.Logger; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.jdbc.core.JdbcTemplate; @Configuration public class TestConfig { @Mock JdbcTemplate jdbcTemplate; @Mock Logger logger; TestConfig(){ MockitoAnnotations.initMocks(this); } @Bean public RCMatchDaoImpl getRCMatchDaoImpl() { return new RCMatchDaoImpl(); } @Bean public JdbcTemplate jdbcTemplate(){ return jdbcTemplate; } @Bean public Logger logger(){ return logger; } }
Answer:
I did use this (with Mockito 1.10.19):
when(jdbcTemplate.queryForObject(eq(Constants.FETCH_DEPOSIT_POSTED_AMT), eq(BigDecimal.class), anyVararg())).thenReturn(depositPostedAmt); when(jdbcTemplate.queryForObject(eq(Constants.FETCH_CLAIM_POSTED_AMOUNT), eq(BigDecimal.class), anyVararg())).thenReturn(claimPostedAmt);
and that is working as expected. Output:
10 0
as expected.
Some reading: http://site.mockito.org/mockito/docs/current/org/mockito/ArgumentMatchers.html#anyVararg()
Code used:
import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.test.context.support.AnnotationConfigContextLoader; import java.lang.reflect.Field; import java.lang.reflect.Modifier; import java.math.BigDecimal; import java.sql.SQLException; import java.util.ArrayList; import java.util.List; import static org.mockito.Matchers.*; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.when; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes = RCMatchDaoImplTest.TestConfig.class, loader = AnnotationConfigContextLoader.class) public class RCMatchDaoImplTest { @Autowired private RCMatchDaoImpl service; @Autowired private JdbcTemplate jdbcTemplate; @Autowired private Logger logger; private RemitBean remitBean; private List<RemitBean> remitBeanList; private BigDecimal depositPostedAmt, claimPostedAmt, remitAmount; private ClaimVO claim; private List<ClaimVO> claims; @Before public void setUp() throws NoSuchFieldException, SecurityException, Exception { /* Set dependencies*/ service.setJdbcTemplate(jdbcTemplate); setFinalStatic(RCMatchDaoImpl.class.getDeclaredField("logger"), logger); remitBean = new RemitBean(); remitBeanList = new ArrayList<>(); claim = new ClaimVO(); claims = new ArrayList<>(); remitBeanList.add(remitBean); depositPostedAmt = new BigDecimal(-10); claimPostedAmt = new BigDecimal(-10); remitAmount = new BigDecimal(20); claims.add(claim); } private static void setFinalStatic(Field field, Object newValue) throws Exception { field.setAccessible(true); Field modifiersField = Field.class.getDeclaredField("modifiers"); modifiersField.setAccessible(true); modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL); field.set(null, newValue); } @Test public void testLucenePost_refund_success() throws SQLException { /* Set Data */ remitBean.setRemitType("R"); remitBean.setRemitAmt(remitAmount); remitBean.setDepositId(6866418); remitBean.setClaims(claims); depositPostedAmt = depositPostedAmt.add(new BigDecimal(20)); claimPostedAmt = claimPostedAmt.add(new BigDecimal(10)); claim.setClaimId(6866418); claim.setContractNum("100"); Object[] depositParams = new Object[]{6866418}; Object[] claimParams = new Object[]{6866418, "100"}; /* Record Invocations*/ when(jdbcTemplate.queryForObject(eq(Constants.FETCH_DEPOSIT_POSTED_AMT), eq(BigDecimal.class), anyVararg())).thenReturn(depositPostedAmt); when(jdbcTemplate.queryForObject(eq(Constants.FETCH_CLAIM_POSTED_AMOUNT), eq(BigDecimal.class), anyVararg())).thenReturn(claimPostedAmt); doNothing().when(logger).error(anyString()); /* Play the Service */ service.lucenePost(remitBeanList); /* Verify Results */ /* reset data to original value as in SetUp method*/ } @Configuration public static class TestConfig { @Mock JdbcTemplate jdbcTemplate; @Mock Logger logger; TestConfig() { MockitoAnnotations.initMocks(this); } @Bean public RCMatchDaoImpl getRCMatchDaoImpl() { return new RCMatchDaoImpl(); } @Bean public JdbcTemplate jdbcTemplate() { return jdbcTemplate; } @Bean public Logger logger() { return logger; } } public static class RCMatchDaoImpl { public static final Logger logger = LoggerFactory.getLogger(RCMatchDaoImpl.class); private JdbcTemplate jdbcTemplate; public void setJdbcTemplate(final JdbcTemplate jdbcTemplate) { this.jdbcTemplate = jdbcTemplate; } public void lucenePost(final List<RemitBean> remitBeanList) { for (RemitBean remitBean : remitBeanList) { System.out.println(jdbcTemplate.queryForObject(Constants.FETCH_DEPOSIT_POSTED_AMT, BigDecimal.class, new Object[]{remitBean.getDepositId()})); for (ClaimVO claimVO : remitBean.getClaims()) { System.out.println(jdbcTemplate.queryForObject(Constants.FETCH_CLAIM_POSTED_AMOUNT, BigDecimal.class, new Object[]{claimVO.getClaimId(), remitBean.getContractNum()})); } } } } public static class RemitBean { private String remitType; private BigDecimal remitAmt; private int depositId; private List<ClaimVO> claims; private Object contractNum; public void setRemitType(final String remitType) { this.remitType = remitType; } public void setRemitAmt(final BigDecimal remitAmt) { this.remitAmt = remitAmt; } public void setDepositId(final int depositId) { this.depositId = depositId; } public int getDepositId() { return depositId; } public void setClaims(final List<ClaimVO> claims) { this.claims = claims; } public List<ClaimVO> getClaims() { return claims; } public Object getContractNum() { return contractNum; } } public static class ClaimVO { private int claimId; private String contractNum; public void setClaimId(final int claimId) { this.claimId = claimId; } public int getClaimId() { return claimId; } public void setContractNum(final String contractNum) { this.contractNum = contractNum; } } static class Constants { public static final String FETCH_DEPOSIT_POSTED_AMT = "1"; public static final String FETCH_CLAIM_POSTED_AMOUNT = "2"; } }
Question:
When I am executing the second test testExecute_noException, still its returning null pointer exception. For first test is returning null pointer exception is valid, but for the second test I need to continue with the next lines tests. Please refer more details in below.
Actual Code:
import org.springframework.batch.core.StepContribution; import org.springframework.batch.core.scope.context.ChunkContext; import org.springframework.batch.core.step.tasklet.Tasklet; import org.springframework.batch.repeat.RepeatStatus; import org.springframework.jdbc.core.JdbcTemplate; import javax.sql.DataSource; public class SimpleQueryExecutorTasklet implements Tasklet { private DataSource dataSource; private String sql; public void setDataSource(DataSource dataSource) { this.dataSource = dataSource; } public void setSql(String sql) { this.sql = sql; } @Override public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception { new JdbcTemplate(this.dataSource).execute(this.sql); return RepeatStatus.FINISHED; } }
Test Code:
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 org.powermock.api.mockito.PowerMockito; import org.springframework.batch.core.StepContribution; import org.springframework.batch.core.scope.context.ChunkContext; import org.springframework.jdbc.core.JdbcTemplate; import javax.sql.DataSource; @RunWith(MockitoJUnitRunner.class) public class SimpleQueryExecutorTaskletTest { @InjectMocks SimpleQueryExecutorTasklet simpleQueryExecutorTasklet; @Mock StepContribution stepContribution; @Mock ChunkContext chunkContext; @Mock JdbcTemplate jdbcTemplate; @Mock DataSource dataSource; String sql="select * from abc;"; @Before public void setUp() throws Exception { simpleQueryExecutorTasklet.setDataSource(dataSource); simpleQueryExecutorTasklet.setSql(sql); PowerMockito.whenNew(JdbcTemplate.class).withAnyArguments().thenReturn(jdbcTemplate); } @Test(expected = NullPointerException.class) public void testExecute() throws Exception { simpleQueryExecutorTasklet.execute(stepContribution,chunkContext); } @Test public void testExecute_noException() throws Exception { Mockito.doNothing().when(jdbcTemplate).execute(Mockito.any(String.class)); simpleQueryExecutorTasklet.execute(stepContribution,chunkContext); // Here will write some assertions } }
Exception log from Junit execution:
java.lang.NullPointerException at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:390) at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:428) at com.xxxxxx.api.accel.operations.SimpleQueryExecutorTasklet.execute(SimpleQueryExecutorTasklet.java:29) at com.xxxxxx.api.accel.operations.SimpleQueryExecutorTaskletTest.testExecute_noException(SimpleQueryExecutorTaskletTest.java:61) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44) at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15) at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41) at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20) at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:28) at org.junit.runners.BlockJUnit4ClassRunner.runNotIgnored(BlockJUnit4ClassRunner.java:79) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:71) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:49) at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193) at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52) at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191) at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42) at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184) at org.junit.runners.ParentRunner.run(ParentRunner.java:236) at org.mockito.internal.runners.JUnit45AndHigherRunnerImpl.run(JUnit45AndHigherRunnerImpl.java:37) at org.mockito.runners.MockitoJUnitRunner.run(MockitoJUnitRunner.java:62) at org.junit.runner.JUnitCore.run(JUnitCore.java:157) at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68) at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47) at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242) at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)
Answer:
You can try below code
@RunWith(SpringJUnit4ClassRunner.class) public class DaoImplTests{ @Autowired private Dao dao; @Mock JdbcTemplate jdbcTemplate; @Test public void testUsingMockito() { try { User mockedUserInfo = new User(); //setters mockedUserInfo.setXXX; mockedUserInfo.setYYY; Mockito.when(((JdbcDaoSupport)dao.getTemplate())).thenReturn(jdbcTemplate); Mockito.when(jdbcTemplate.queryForObject(Mockito.anyString(), Mockito.any(Object[].class), Mockito.any(RowMapper.class))).thenReturn(mockedUserInfo); User userInfo = dao.getUserInfo(""); Assert.assertNotNull(userInfo); Assert.assertEquals(mockedUserInfo.getXXX(), userInfo.getXXX()); //few more assertions } catch (Exception e) { Assert.fail(" : " + e.getMessage()); } } }
Question:
I wrote a test case but I get a null pointer exception at the return KeyHolder.getKey()
line.
My test case looks like this:
@InjectMocks private UserDAOImpl userDAO; @Mock private JdbcTemplate jdbcTemplate; @Mock private KeyHolderFactory keyHolderFactory; @Before public void setup() { MockitoAnnotations.initMocks(this); ReflectionTestUtils.setField(userDAO, "jdbcTemplate", jdbcTemplate); } @Test public void testCreateUser() { KeyHolder keyHolder = mock(GeneratedKeyHolder.class); when(keyHolderFactory.newKeyHolder()).thenReturn(keyHolder); User user = getUserInfo(); Map<String,Object> map = new HashMap<>(); map.put("id",1L); when(keyHolder.getKeys()).thenReturn(map); when(keyHolder.getKey()).thenReturn(1L); when(jdbcTemplate.update(Mockito.any(PreparedStatementCreator.class), Mockito.any(KeyHolder.class))).thenReturn(1); assertEquals(1L, userDAO.createUser(user)); }
And the method looks like this:
@Override public long createUser(User user) { KeyHolder keyHolder = new GeneratedKeyHolder(); jdbcTemplate.update(connection -> { PreparedStatement ps = connection .prepareStatement("insert into user (address, first_name,last_name, email, password, phone_number, is_init, is_system_admin, created_at)" + " values( ?, ?, ?, ?, ?, ?, ?, ?,?)", Statement.RETURN_GENERATED_KEYS); ps.setString(1, user.getAddress()); ps.setString(2, user.getFirstName()); ps.setString(3, user.getLastName()); ps.setString(4, user.getEmail()); ps.setString(5, user.getPassword()); ps.setString(6, user.getPhone()); ps.setBoolean(7, user.isActive()); ps.setBoolean(8, user.isSystemAdmin()); ps.setDate(9, new Date(Date.from((user.getCreatedAt().toInstant())).getTime())); return ps; }, keyHolder); return (long) keyHolder.getKey(); }
I have created an interface KeyHolderFactory
:
public interface KeyHolderFactory { KeyHolder newKeyHolder(); }
And the implementation of this interface is as follows:
public class GeneratedKeyHolderFactory implements KeyHolderFactory { public KeyHolder newKeyHolder() { return new GeneratedKeyHolder(); } }
Can someone help me to find a solution?
Answer:
Your issue is next :
In test class you have Mocked bin KeyHolderFactory
and this is correct. Then you create mocked KeyHolder
, describe it's behavior and make KeyHolderFactory
return KeyHolder
when it is asked. Everything looks OK except next :
On your code class method you create new KeyHolder
using new GeneratedKeyHolder()
and this new KeyHolder
doesn't relate to those mocked instance that you have in your test class. It is absolutely different objects. That one which is in your test class - is a mock, and will follow your scenario. But that one, in your tested class method, is another object, which of course don't know what to do when you execute keyHolder.getKey()
.
Solution :
You have injected KeyHolderFactory
in your test and well configured it's behavior. Just inject this into your test class as well and use it in your method to create KeyHolder
using keyHolderFactory.newKeyHolder()
instead of new GeneratedKeyHolder()
Question:
Hi i need help mocking the below statement.
List<String> testString= jdbcTemplate.query(queryString, new Object[] { someStringParameter }, new testMapper());
Answer:
Got this working using the below mock
when(jdbcTemplateMock.query(anyString(), Matchers.<Object[]> anyVararg(),
Matchers.any(testMapper.class)))
Question:
How do I mock the DriverManager.getConnection() method?
I want to test my method setUpConnectiontoDB()
I tried it with PowerMock, easyMock and Mokito itself. I didn't find anything usefull.
My Code:
import java.io.FileInputStream; import java.io.IOException; import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; import java.util.Properties; public class MysqlDAO implements DAO { private final Properties properties = new Properties(); public MysqlDAO(String configPath) { loadProperties(configPath); } private Properties loadProperties(String configPath) { try { properties.load(new FileInputStream(configPath)); } catch (IOException e) { e.printStackTrace(); } return this.properties; } @Override public Connection setUpConnectionToDB() { try { Class.forName("com.mysql.jdbc.Driver"); return DriverManager.getConnection( properties.getProperty("url"), properties.getProperty("user"), properties.getProperty("passwd")); } catch (ClassNotFoundException | SQLException e) { e.printStackTrace(); } return null; } }
Answer:
Some notes on that:
Class.forName("com.mysql.jdbc.Driver");
This line is obsolete since JDBC 4.0. You should be able to run the code without. Or if you think you need it at least abstract it as well to do
Class.forName(properties.getProperty("dbdriver", "com.mysql.jdbc.Driver");
Once that's been taken care of, who says you have to mock it? It's much easier to actually run it.
You could just as well use an in memory database (like h2) for testing and check your code for that. All you'd change would be your url, user and passwd properties.
This would be some example properties for use with h2:
dbdriver = org.h2.Driver url = jdbc:h2:mem:test user = sa passwd = sa
That way, you not only take care of your unit-test for setUpConnectionToDB() but could later use that connection for methods that expect some data in that database.
Question:
I am new to Mockito and trying to cover following source code:
jdbcOperations.update(insertRoleQuery,new Object[]{"menuName","subMenuName","subSubMenuName","aa","bb","cc","role"});
In this query is taking 7 string parameters. I have written the mockito test case for the code and it's also covering the source code but I am not sure whether it's the correct way or not.
when(jdbcOperations.update(Mockito.anyString(), new Object[]{Mockito.anyString(),Mockito.anyString(),Mockito.anyString(),Mockito.anyString(),Mockito.anyString(),Mockito.anyString(),Mockito.anyString()})).thenThrow(runtimeException);
Please suggest if i am doing it right way or not.
Thanks
Answer:
As per the docs, you can either use exact values, or argument matchers, but not both at the same time:
Warning on argument matchers:
If you are using argument matchers, all arguments have to be provided by matchers.
If you do mix them, like in your sample, mockito will complain with something similar to
org.mockito.exceptions.misusing.InvalidUseOfMatchersException: Invalid use of argument matchers! 2 matchers expected, 1 recorded: -> at MyTest.shouldMatchArray(MyTest.java:38) This exception may occur if matchers are combined with raw values: //incorrect: someMethod(anyObject(), "raw String"); When using matchers, all arguments have to be provided by matchers. For example: //correct: someMethod(anyObject(), eq("String by matcher")); For more info see javadoc for Matchers class.
In your case you don't seem to care about the array contents, so you can just use any()
:
when(jdbcOperation.update(anyString(), any())).thenThrow(runtimeException);
If you want to at least check the number of parameters, you can use either
when(jdbcOperation.update(anyString(), argThat(array -> array.length == 7))).thenThrow(runtimeException);
when(jdbcOperation.update(anyString(), argThat(arrayWithSize(7)))).thenThrow(runtimeException);
If you're interested in matching certain values, you can use AdditionalMatchers.aryEq(expectedArray)
, or just Mockito.eq(expectedArray)
which has a special implementation for arrays, but I fell that the first one expresses your intent in a clearer way.
when(jdbcOperation.update(anyString(), aryEq(new Object[]{"whatever"}))).thenThrow(runtimeException);
Question:
I'm writing a test case for Email DAO layer. which is something like:
@Repository @PropertySource({ "classpath:/query.properties" }) public class DaoLayerImpl implements DaoLayerDao { /** The jdbc template. */ @Qualifier("mariaJdbcTemplate") @Autowired private JdbcTemplate jdbcTemplate; /** The find staged query. */ @Value("${someQuery}") String someQuery; @Override public List<SomeBean> getData() throws MariaDbException { List<SomeBean> listOfData = new ArrayList<>(); try { listOfData = jdbcTemplate.query(someQuery, new BeanPropertyRowMapper<SomeBean>(SomeBean.class)); } catch (RuntimeException e) { logger.error("RuntimeException in ", e); } return listOfData; } }
The Test case for this layer is :
@RunWith(SpringRunner.class) @ActiveProfiles("test") @PropertySource("classpath:application-test.properties") public class EmailDaoLayerTest { @MockBean JdbcTemplate jdbcTemplate; @InjectMocks DaoLayerImpl dao; @Before public void setup() { MockitoAnnotations.initMocks(this); jdbcTemplate = Mockito.mock(JdbcTemplate.someQuery); ReflectionTestUtils.setField(dao, "jdbcTemplate", jdbcTemplate); } @Test public void testCaseForGetData() throws Exception { List<SomeBean> beanObject = new ArrayList<>(); beanObject.add(new SomeBean()); beanObject.add(new SomeBean()); beanObject.add(new SomeBean()); System.out.println(beanObject.size()); // 3 when(jdbcTemplate.query("someQuery", new BeanPropertyRowMapper<SomeBean>(SomeBean.class))).thenReturn(beanObject); List<SomeBean> obj = dao.getData(); System.out.println(obj.size()); //0 System.out.println("Done"); } }
After mocking the object size comes out to be 0 instead of 3. The size of the object before returning is 3. when i actually hitted the DAO, the size of the object comes out to be 0, whereas i had already mocked the jdbc template using when-then .
What is the correct way to mock Bean Property Row Mapper class?
Answer:
Let me answer the question and then criticize your approach, maybe it will help to better understand how the solution should look like at the end.
So to answer your question:
Technically you can probably do something like:
import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.any; ... Mockito.when(jdbcTemplate.query(eq("someQuery"), any(BeanPropertyRowMapper.class)).thenReturn(....);
However, you should ask yourself what exactly are you trying to test here? You have a relatively expensive integration test here that runs the Spring Context (it works with SpringRunner) and creates many objects under the hood.
However based on the method to be tested - I don't see that there is any "meaningful" (subject to tests) code to be tested. You could test that given the query, the BeanPropertyRowMapper indeed can convert the response to instances of SomeBean
but then again you mock it and it doesn't really run.
You could check that the query you've prepared runs against the Database and returns the expected results, but it doesn't seem that you prepare any database here.
So If the purpose is coverage - then yes you will be covered, but the tests are not about the coverage, but about making you "sure" that your code works properly. In this case, running the Spring Driven integration Test (with application context and everything) seems to be a huge overkill, MockitoRunner
could do the job
Question:
I am new for Junit and Mockito and i am not understand how to write test case for below JdbcTemplate and i tried but getting exception ,Can some one help me please
org.mockito.exceptions.misusing.InvalidUseOfMatchersException: Invalid use of argument matchers!
Code
@Repository public class BaaisnEvcIdMSRepository { @Autowired private JdbcTemplate jdbcTemplate; @Transactional public RowMapperServerResponse getQueryEvcidRepository(BaaisnEvcIdRequest baaisnEvcIdRequest) { RowMapperServerResponse rowMapperServerResponse = jdbcTemplate.queryForObject( "select * from Master_Circuit WHERE master_ckt_id = ( select max(master_ckt_id) from master_circuit WHERE product = ? AND id_type = ?)", new Object[]{baaisnEvcIdRequest.getProduct_type(),baaisnEvcIdRequest.getLata()}, new BaaisnRowMapper()); return rowMapperServerResponse; } }
test class
public class BaaisnEvcIdMSRepositoryTest { @InjectMocks BaaisnEvcIdMSRepository baaisnEvcIdMSRepository; @Mock JdbcTemplate jdbcTemplate; @Before public void setup() { MockitoAnnotations.initMocks(this); } @Test public void getQueryEvcidRepositoryTest() { when(jdbcTemplate.queryForObject(eq(ArgumentMatchers.anyString()), refEq(new Object[]{ArgumentMatchers.anyInt()}), eq(String.class))).thenReturn("data"); verify(jdbcTemplate, times(1)).queryForObject(eq(ArgumentMatchers.anyString()), refEq(new Object[]{ArgumentMatchers.anyInt()}), eq(String.class)); } }
Answer:
The InvalidUseOfMatchersException
is coming from your use of eq(ArgumentMatchers.anyString())
and refEq(new Object[]{ArgumentMatchers.anyInt()})
. You are not supposed to wrap ArgumentMatchers
inside anything else.
You also seem to aim at the wrong queryForObject
method. It should be this one
instead.
As mentioned before you need to call the method under test
before doing the verification.
@Test public void getQueryEvcidRepositoryTest() { // use a real `BaaisnEvcIdRequest` object if you can BaaisnEvcIdRequest req = Mockito.mock(BaaisnEvcIdRequest.class); Mockito.when(req.getProduct_type()).thenReturn(1); Mockito.when(req.getLata()).thenReturn(new Object()); Object[] array = new Object[]{req.getProduct_type(),req.getLata()}; Mockito.when(jdbcTemplate.queryForObject(Mockito.anyString(), Mockito.eq(array), Mockito.any(RowMapper.class))) .thenReturn("data"); baaisnEvcIdMSRepository.getQueryEvcidRepository(req); Mockito.verify(jdbcTemplate, Mockito.times(1)) .queryForObject(Mockito.anyString(), Mockito.eq(array), Mockito.any(RowMapper.class)); }
Question:
I'm trying to mock (Spring boot, JUnit, Oracle)
jdbcTemplate.execute(CallableStatementCreator, CallableStatementCallback); public class ExceptionTest { @Autowired private SecurityDAOImpl securityDAOImplMock; @Mock private JdbcTemplate jdbcTemplate; @Autowired private JdbcTemplate resetJdbcTemplate; @Before public void init() throws Exception { securityDAOImplMock = spy(new SecurityDAOImpl()); MockitoAnnotations.initMocks(this); } @SuppressWarnings("unchecked") @Test(expected = SecurityDAOException.class) public void testUpdateProfileException() { DataAccessException dataAccessException = new DataAccessException("Mock Exception", new Exception("Mocked DataAccessException")) { private static final long serialVersionUID = 1L; }; ReflectionTestUtils.setField(securityDAOImplMock, "jdbcTemplate", jdbcTemplate); doThrow(dataAccessException).when(jdbcTemplate).execute(any(), any()); securityDAOImplMock.isTooManyFailedAttempt("", 7, "", ""); } @After public void reset() { ReflectionTestUtils.setField(securityDAOImplMock, "jdbcTemplate", resetJdbcTemplate); } }
I'm getting the following compile time exception:
The method execute(PreparedStatementCreator, PreparedStatementCallback<Object>) is ambiguous for the type
on this line
doThrow(securityDAOException).when(jdbcTemplate).execute(any(), any());
How to mock jdbcTemplate.execute(callableStatementCreator, callableStatementCallback).How to make this work?
Answer:
Method JdbcTemplate.execute()
is overloaded.
So when you mock it using matcher any()
the compiler simply does not know which method you actually mean and throws an error.
To fix that supply a class in the matcher to resolve this ambiguity.
For example, if you want to mock
JdbcTemplate.execute(PreparedStatementCreator psc, PreparedStatementCallback<T> action)
use
doThrow(securityDAOException).when(jdbcTemplate).execute(any(PreparedStatementCreator.class), any(PreparedStatementCallback.class));
Question:
I am using spring with jdbcTemplate for my app and I want to test DaoImpl class. There is implementation for insertion, updation and retrieval operation
Dao class Method
//dummy class public class PlayerDAOImpl implements PlayerDAO { @Autowired private JdbcTemplate jdbcTemplate; public Integer getPlayer(int playerId) { String sql = "SELECT ccount(1) FROM PLAYER WHERE PLAYER_ID = ?"; return (jdbcTemplate. queryForObject("Query", new Object[]{playerId}, Integer.class)!=0); //here only throws exception } //other methods }
and for that I have written Test class which execute successfully for insertion and updation but while retrieving it is giving nullpointer exception.
@RunWith(MockitoJUnitRunner.class) class Test{ @InjectMocks PlayerDAOImpl dao; @Mock JdbcTemplate jdbcTemplate; @Test public void retrieveResult(){ Mockito.when(dao.getPlayer(int playerId)).thenReturn(false); //Assert Statement }}
I have googled/tried but not found solution which worked for me. So how to test that method or inject jdbcTemplate so that it will succeed.
Thanks for Help!!
Answer:
The problem is that you are trying to mock the class under test (PlayerDAOImpl
) instead of its dependency (JdbcTemplate
).
Change you mock to something like:
Mockito.when(jdbcTemplate.queryForObject(Mockito.any(), Mockito.any(), Mockito.any()).thenReturn(COUNT);
Where COUNT
is an Integer
, and then write your assertions on the return value of dao.getPlayer
.
Question:
I'm trying using mockito to mock jdbcTemplate and call the method query passing it parameters using Object[]{}.
I'm making the unit test for my DAO layer I want to mock jdbcTemplate and call the method query and pass the sql string,a RowMapper and parameters using Object[] {}
public List<EntityType> myDaoMethod(Date fechaInicio, Date fechaFin) throws NotDataFoundException { log.info("entering => myDaoMethod"); log.info("param => fechaInicio :" + fechaInicio); log.info("param => fechaFin :" + fechaFin); log.debug("Se ejecutando consulta..."); try { List<EntityType> query = jdbcTemplate.query(QueryStrs.MY_QUERY, new Object[] {fechaInicio, fechaFin}, new BeanPropertyRowMapper<EntityType>(EntityType.class)); log.debug("Se ejecuto consulta. "); return query; }catch(DataAccessException e) { log.error("No se encontro informacion en la consulta myDaoMethod (2)", e); throw new NotDataFoundException(e); }finally { log.info("exiting => myDaoMethod"); } }
@Mock private JdbcTemplate jdbcTemplate; @Test public void myTestMethod() throws NotDataFoundException { List<EntityType> listValue = new ArrayList<>(); listValue.add(new EntityType((short) 2, "modem 2")); listValue.add(new EntityType((short) 1, "modem")); when(jdbcTemplate.query(any(String.class),any(Object[].class), any(BeanPropertyRowMapper.class))).thenReturn(listValue); MyDao dao = new MyDaoImpl(jdbcTemplate); List<EntityType> otrasAdicionalesPorRangoFecha = dao.myDaoMethod(any(Date.class), any(Date.class)); Assert.assertNotNull(otrasAdicionalesPorRangoFecha); Assert.assertTrue(!otrasAdicionalesPorRangoFecha.isEmpty()); // Assert.assertArrayEquals(listValue.toArray(), otrasAdicionalesPorRangoFecha.toArray()); }
The trace result is
org.mockito.exceptions.misusing.InvalidUseOfMatchersException: Invalid use of argument matchers! 3 matchers expected, 2 recorded: -> at com.oracle.reporter.tddtest.rrhhcomision.OtrasAdicionalesDaoTest.testBuscarOtrasAdicionalesPorFecha(OtrasAdicionalesDaoTest.java:80) -> at com.oracle.reporter.tddtest.rrhhcomision.OtrasAdicionalesDaoTest.testBuscarOtrasAdicionalesPorFecha(OtrasAdicionalesDaoTest.java:80)
This exception may occur if matchers are combined with raw values: //incorrect: someMethod(anyObject(), "raw String"); When using matchers, all arguments have to be provided by matchers. For example: //correct: someMethod(anyObject(), eq("String by matcher"));
Answer:
The problem is that your dao
is not a mocked object, so you are not supposed
to pass matchers at this point.
Wrong:
dao.myDaoMethod(any(Date.class), any(Date.class));
Correct:
dao.myDaoMethod(new Date(1), new Date(2));
Question:
I want to know how to mock the particular code using Mockito:
List<Map<String, Object>> list = jdbcTemplate.queryForList( sqlQuery, new Object[] { inflowId } );
I tried the following code:
Mockito.doReturn(list) .when(jdbcTemplate) .queryForList(Mockito.anyString(), Mockito.any(Class.class));
and:
when( jdbcTemplate.queryForList(Mockito.anyString(), Mockito.any(Object[].class)) ).thenReturn(list);
My problem is that particular method is not getting mocked in JUnit. When the method is called, it returns null
whereas it should return the list.
Answer:
This should work:
import org.hamcrest.CoreMatchers; import org.junit.Assert; import org.junit.Test; import org.mockito.ArgumentMatchers; import org.mockito.Mockito; import org.springframework.jdbc.core.JdbcTemplate; import java.util.ArrayList; import java.util.List; import java.util.Map; public class DemoTest { @Test public void mockJdbcTemplate() { JdbcTemplate mockTemplate = Mockito.mock(JdbcTemplate.class); List<Map<String, Object>> mockResult = new ArrayList<>(); Mockito.when(mockTemplate.queryForList(Mockito.anyString(), ArgumentMatchers.<Object>any())).thenReturn(mockResult); // Alternatively: // when(mockTemplate.queryForList(anyString(), Mockito.<Object>any())).thenReturn(mockResult); String query = "some query"; Object[] params = new Object[]{1}; List<Map<String, Object>> returnedResult = mockTemplate.queryForList(query, params); Assert.assertThat(returnedResult, CoreMatchers.sameInstance(mockResult)); } }
The trick is to use ArgumentMatchers.<Object>any()
as there are multiple queryForList
method implementations and the one we want to mock receives a varargs parameter.
Question:
I can`t find info how to set up separate H2 db for JUnit in servlets. All info about Spring, but i need H2 to test my DAO and controllers in Servlets app. Will be glad about any info.
Answer:
The problem was solved with a bit weird way. In my AuthorService DAO class i created constructor which take a connection. And depends on the situation i inject right connetion with AbstractFactory.
Question:
I try to learn to test my projects correctly and continuously. Unfortunately there are a few things I don‘t understand since there are a lot of different opinions on the topic. What I don’t get is how to decide which classes are „worth“ testing them. As an example I took the example JDBC connection class from oracle:
public Connection getConnection() throws SQLException { Connection conn = null; Properties connectionProps = new Properties(); connectionProps.put("user", this.userName); connectionProps.put("password", this.password); if (this.dbms.equals("mysql")) { conn = DriverManager.getConnection( "jdbc:" + this.dbms + "://" + this.serverName + ":" + this.portNumber + "/", connectionProps); } else if (this.dbms.equals("derby")) { conn = DriverManager.getConnection( "jdbc:" + this.dbms + ":" + this.dbName + ";create=true", connectionProps); } System.out.println("Connected to database"); return conn; }
I know I can mock objects to be able to look at the class more isolated. Is it even useful to test a class like this, or can I benefit from doing something like this, to see if a connection could theoretically be made?
public class TestClass { @Mock private Connection conn; @Mock private Database database; @BeforeEach public void setUp() throws Exception { assertNotNull(database); when(database.getConnection()).thenReturn(conn); } }
Answer:
Mocking in unit tests helps you test the part of your code that would otherwise be using a resource. Using it to test a class where it's only purpose is to establish connection to a resource makes no sense.
This functionality will be tested during an integration testing. See more on integration and unit testing here
Question:
In my Spring Boot project I have two datasources:
@Primary @Bean(name = "pgDatasource") public BasicDataSource dataSource() { BasicDataSource dataSource = new BasicDataSource(); dataSource.setDriverClassName(env.getProperty("spring.datasource.dbcp2.driver-class-name")); dataSource.setUrl(env.getProperty("spring.datasource.dbcp2.url")); dataSource.setUsername(env.getProperty("spring.datasource.dbcp2.username")); dataSource.setPassword(env.getProperty("spring.datasource.dbcp2.password")); dataSource.setMaxActive(Integer.valueOf(env.getProperty("spring.datasource.dbcp2.max-total"))); dataSource.setMaxIdle(Integer.valueOf(env.getProperty("spring.datasource.dbcp2.max-idle"))); dataSource.setInitialSize(Integer.valueOf(env.getProperty("spring.datasource.dbcp2.initial-size"))); return dataSource; } @Bean(name = "h2Datasource") public BasicDataSource h2DataSource() { BasicDataSource dataSource = new BasicDataSource(); dataSource.setDriverClassName(env.getProperty("spring.h2.datasource.driver-class-name")); dataSource.setUrl(env.getProperty("spring.h2.datasource.url")); dataSource.setUsername(env.getProperty("spring.h2.datasource.username")); dataSource.setPassword(env.getProperty("spring.h2.datasource.password")); Resource initData = new ClassPathResource("scripts/inmem.sql"); DatabasePopulator databasePopulator = new ResourceDatabasePopulator(initData); DatabasePopulatorUtils.execute(databasePopulator, dataSource); return dataSource; }
Here datasource for PostgreSQL is a primary bean. In my several tests I would like to run a script against h2 database. For that I am trying to use @Sql
annotation. However, if I use @Sql
, it runs script against pgDatasource
. I could configure h2 as a primary bean for those tests, but test methods' bodies are dependent on the configuration where pgDatasource
is a primary bean.
Test sample:
@Test @Sql(scripts = "/clean_login_attempts.sql", executionPhase = AFTER_TEST_METHOD) void loginAttemptsIncrementTheCount() throws Exception { unsuccessfulLoginRequest(); unsuccessfulLoginRequest(); unsuccessfulLoginRequest(); LoginAttempt loginAttempt = loginAttemptService.getAttempt("admin"); assertEquals(3, loginAttempt.getAttempt()); }
Is it possible to configure datasource for org.springframework.test.context.jdbc.Sql
annotation?
Answer:
Adding config = @SqlConfig(dataSource = "h2Datasource", transactionManager = "h2tx") solved the issue.
@Test @Sql(scripts = "/clean_login_attempts.sql", executionPhase = AFTER_TEST_METHOD, config = @SqlConfig(dataSource = "h2Datasource", transactionManager = "h2tx")) void loginAttemptsIncrementTheCount() throws Exception { unsuccessfulLoginRequest(); unsuccessfulLoginRequest(); unsuccessfulLoginRequest(); LoginAttempt loginAttempt = loginAttemptService.getAttempt("admin"); assertEquals(3, loginAttempt.getAttempt()); }
Question:
What is the better approach to test springJdbcTemplate using junit and mockito. How to mock jdbcTemplate or NamedParameterJdbcTemplate.
Answer:
How to mock jdbcTemplate or NamedParameterJdbcTemplate.
Don't mock them. You want to test that data are correctly inserted in and retrieved from the database. If you mock them, the value of the tests will be weak.
So for your unit tests, just set the datasource to connect to a in-memory database and test the methods you are using.
You can rely on the 3.8.5. Testing data access logic with an embedded databasedocumentation :
Question:
In the test case for service,I am unable to resolve dependency of dao class and JdbcTemplate.
public class TestPromotionUsingJunit { @InjectMocks private ItemService itemService; @Mock private ItemDAOImpl itemDAOImpl; @Mock private JdbcTemplate jdbcTemplate; @Before public void setupMock() { MockitoAnnotations.initMocks(this); itemService = new ItemService(); } @Test public void testFindMax() { Product pro1 = new Product(); pro1.setPluCode("4900692627408"); pro1.setCategoryNo("2"); pro1.setCategoryName("Women"); pro1.setProductName("T-Shirt10163"); pro1.setColor("CY"); pro1.setSize("32"); BigDecimal b1 = new BigDecimal(94.00); BigDecimal b2 = new BigDecimal(8); pro1.setPrice(b1); pro1.setTax(b2); Product pro2 = new Product(); pro2.setPluCode("4900692627408"); assertEquals(pro1.getPrice(), itemService.getItem(pro1)); } }
Here ItemService should return product object but it returns null. Due to internally unable to solve dependency.
Answer:
@InjectMocks creates a mock instance of itemService, but then
itemService = new ItemService();
creates a real instance and throws the mock away. In setupMock(), after itemService is constructed, try adding the equivalent of this:
itemService.setItemDao(itemDAOImpl);
So you'll have a real ItemService which uses a mock DAO.
Then in testFindMax() configure the DAO to return pro1, something like this:
when(itemDAOImpl.getItem(...)).thenReturn(pro1);