Hot questions for Using Mockito in dao
Question:
I've started to discovered Mockito library and there is a question for which I didn't find the proper answer.
If I have for example such method in my UserDAO class that saves user in database:
public class UserDAO{ ... public void create(User user) { Connection connection = null; PreparedStatement pstmt = null; ResultSet generatedKeys = null; try { connection = getConnection(); pstmt = connection.prepareStatement(INSERT_USER, PreparedStatement.RETURN_GENERATED_KEYS); int counter = 1; pstmt.setString(counter++, user.getFirstName()); pstmt.setString(counter++, user.getLastName()); pstmt.setString(counter++, user.getEmail()); pstmt.setString(counter++, user.getPassword()); pstmt.setString(counter++, user.getRole()); pstmt.setString(counter, user.getLang()); pstmt.execute(); connection.commit(); generatedKeys = pstmt.getGeneratedKeys(); if (generatedKeys.next()) { user.setId(generatedKeys.getInt(Fields.GENERATED_KEY)); } } catch (SQLException e) { rollback(connection); LOG.error("Can not create a user", e); } finally { close(connection); close(pstmt); close(generatedKeys); } } .... }
How should I test it ?
If I want to test for example a DAO class then I need to create a DataSource
mock, Connection
mock, ResultSet
mock etc ? And so not to test the database itself ?
But what if I want to also test the behavior of dao and database ?
Would you please produce some code samples, links that could be helpful and show best approaches of doing it ?
Answer:
Here is a good start using Mockito to test your UserDAO. This code uses a good amount of the Mockito features, so you can see how to use them. Let me know if you have questions.
import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import javax.sql.DataSource; import org.junit.After; import org.junit.AfterClass; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; import static org.junit.Assert.*; import org.junit.runner.RunWith; import static org.mockito.Matchers.anyInt; import static org.mockito.Matchers.anyString; import org.mockito.Mock; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import org.mockito.runners.MockitoJUnitRunner; @RunWith(MockitoJUnitRunner.class) public class TestUserDAO { @Mock DataSource mockDataSource; @Mock Connection mockConn; @Mock PreparedStatement mockPreparedStmnt; @Mock ResultSet mockResultSet; int userId = 100; public TestUserDAO() { } @BeforeClass public static void setUpClass() throws Exception { } @AfterClass public static void tearDownClass() { } @Before public void setUp() throws SQLException { when(mockDataSource.getConnection()).thenReturn(mockConn); when(mockDataSource.getConnection(anyString(), anyString())).thenReturn(mockConn); doNothing().when(mockConn).commit(); when(mockConn.prepareStatement(anyString(), anyInt())).thenReturn(mockPreparedStmnt); doNothing().when(mockPreparedStmnt).setString(anyInt(), anyString()); when(mockPreparedStmnt.execute()).thenReturn(Boolean.TRUE); when(mockPreparedStmnt.getGeneratedKeys()).thenReturn(mockResultSet); when(mockResultSet.next()).thenReturn(Boolean.TRUE, Boolean.FALSE); when(mockResultSet.getInt(Fields.GENERATED_KEYS)).thenReturn(userId); } @After public void tearDown() { } @Test public void testCreateWithNoExceptions() throws SQLException { UserDAO instance = new UserDAO(mockDataSource); instance.create(new User()); //verify and assert verify(mockConn, times(1)).prepareStatement(anyString(), anyInt()); verify(mockPreparedStmnt, times(6)).setString(anyInt(), anyString()); verify(mockPreparedStmnt, times(1)).execute(); verify(mockConn, times(1)).commit(); verify(mockResultSet, times(2)).next(); verify(mockResultSet, times(1)).getInt(Fields.GENERATED_KEYS); } @Test(expected = SQLException.class) public void testCreateWithPreparedStmntException() throws SQLException { //mock when(mockConn.prepareStatement(anyString(), anyInt())).thenThrow(new SQLException()); try { UserDAO instance = new UserDAO(mockDataSource); instance.create(new User()); } catch (SQLException se) { //verify and assert verify(mockConn, times(1)).prepareStatement(anyString(), anyInt()); verify(mockPreparedStmnt, times(0)).setString(anyInt(), anyString()); verify(mockPreparedStmnt, times(0)).execute(); verify(mockConn, times(0)).commit(); verify(mockResultSet, times(0)).next(); verify(mockResultSet, times(0)).getInt(Fields.GENERATED_KEYS); throw se; } } }
Question:
I am looking for information to build unit test for typical DAO methods (find user by username, etc.) and I found several examples using mocks like this one: http://www.christophbrill.de/de_DE/unit-testing-with-junit-and-mockito/
@Test public void testComeGetSome() { // Mock the EntityManager to return our dummy element Some dummy = new Some(); EntityManager em = Mockito.mock(EntityManager.class); Mockito.when(em.find(Some.class, 1234)).thenReturn(dummy); // Mock the SomeDao to use our EntityManager SomeDao someDao = Mockito.mock(SomeDao.class); Mockito.when(someDao.comeGetSome(1234)).thenCallRealMethod(); Mockito.when(someDao.getEntityManager()).thenReturn(em); // Perform the actual test Assert.assertSame(dummy, someDao.comeGetSome(1234)); Assert.assertNull(someDao.comeGetSome(4321)); }
There is also a similar one in Lasse Koskela's book using EasyMock instead of Mockito.
The thing is: what are we really testing in these examples? We are basically telling through mocks what object the query should return, and then asserting that in fact it returned the object we told it to return.
We are not testing if the query is correct or if it returns a different object or no objects at all (or even more than one object). We cannot test if it returns null when the object does not exist in the database. This line
Assert.assertNull(someDao.comeGetSome(4321));
works because there is no scripted interaction for that argument, not because the object does not exist.
It looks like we are just testing if the method calls the proper methods and objects (em.find).
What is the point of unit testing this? Are there any good frameworks in Java to quickly set up an in memory database and perform tests with it?
Answer:
Your doubts really make sense. Actually there is no need to test DAO with unit tests in most cases because unit tests deal with one layer, but DAO cooperate with database layer.
This article explains this idea: http://www.petrikainulainen.net/programming/testing/writing-tests-for-data-access-code-unit-tests-are-waste/
Hence we should test DAO and database layer with integration tests. Integration tests take into account both DAO and database layer.
This article will provide your with Spring + Hibernate example: https://dzone.com/articles/easy-integration-testing
Question:
I'm new to Java / Mockito and trying to test a Dao method, specifically an exception condition that catches ParseException and throws SQLException.
Here's the Dao code:
public Template saveTemplate(Template template) throws SQLException { logger.debug("Saving template details into the db ", template.getTemplateName()); SimpleDateFormat dt = new SimpleDateFormat("yyyyy-mm-dd hh:mm:ss"); Long date = 0L; try { date = dt.parse(template.getStartTime()).getTime(); } catch (ParseException e) { throw new SQLException("Error while processing date " + template.getTemplateName()); } Long finalDate = date;
My strategy was to mock the SimpleDateFormat.parse()
call so that it throws the ParseException, but that's not working. Not even sure that's a good strategy...
First I tried:
@InjectMocks private SimpleDateFormat simpleDateformat;
but that doesn't work because the SimpleDateFormat constructor requires a parameter, and gets the error:
org.mockito.exceptions.base.MockitoException:
Cannot instantiate @InjectMocks field named 'simpleDateFormat' of type 'class java.text.SimpleDateFormat'.
You haven't provided the instance at field declaration so I tried to construct the instance.
However the constructor or the initialization block threw an exception : null
So then I tried this:
@Mock private SimpleDateFormat simpleDateFormat; @Test(expected = SQLException.class) public void test_save_template_date_parse_error() throws ParseException, SQLException { initMocks(this); Mockito.mockingDetails(simpleDateFormat); Mockito.when(simpleDateFormat.parse(anyString(),new ParsePosition(anyInt()))).thenThrow(new ParseException(anyString(),anyInt())); Template template = new Template(); template.setStartTime("2017-01-02 12:12:12"); template.setTemplateId(1); given(jdbcTemplate.getJdbcOperations()).willReturn(jdbcOperations); templateDAOImpl.saveTemplate(template); }
The resulting error isn't helpful to my unpracticed eye:
org.mockito.exceptions.misusing.InvalidUseOfMatchersException: Misplaced or misused argument matcher detected here: -> at com.macys.etap.ee.dao.TemplateDAOImplTest.test_save_template_date_parse_error(TemplateDAOImplTest.java:77) -> at com.macys.etap.ee.dao.TemplateDAOImplTest.test_save_template_date_parse_error(TemplateDAOImplTest.java:77) You cannot use argument matchers outside of verification or stubbing. Examples of correct usage of argument matchers: when(mock.get(anyInt())).thenReturn(null); doThrow(new RuntimeException()).when(mock).someVoidMethod(anyObject()); verify(mock).someMethod(contains("foo")) This message may appear after an NullPointerException if the last matcher is returning an object like any() but the stubbed method signature expect a primitive argument, in this case, use primitive alternatives. when(mock.get(any())); // bad use, will raise NPE when(mock.get(anyInt())); // correct usage use Also, this error might show up because you use argument matchers with methods that cannot be mocked. Following methods *cannot* be stubbed/verified: final/private/equals()/hashCode(). Mocking methods declared on non-public parent classes is not supported.
So how do I mock this thing and get the error thrown?
Edit: New approach as suggested, mocking Template.getStartTime():
@Test(expected = SQLException.class)
public void test_save_template_date_parse_error() throws ParseException, SQLException {
initMocks(this);
Template templateMock = Mockito.mock(Template.class);
Mockito.when(templateMock.getStartTime()).thenReturn("invalid");
Mockito.mockingDetails(templateMock.getStartTime());
Template template = new Template();
template.setStartTime("2017-01-02 12:12:12");
template.setTemplateId(1);
given(jdbcTemplate.getJdbcOperations()).willReturn(jdbcOperations);
// Fixed per @Daniel Pryden : works now
templateDAOImpl.saveTemplate(templateMock);
}
And now works with the fix.
Answer:
In my opinion, you don't even need Mockito here, you can simply do the following :
Template template = new Template(); template.setStartTime("THIS IS AN INVALID DATE"); template.setTemplateId(1); templateDAOImpl.saveTemplate(template);
And then the SQLException will be thrown.
Question:
I am beyond frustrated because I can't figure this out. I've been over millions of articles and NOTHING is clear on how this is done. I am trying to write a Mockito test just for practice.
I have a spring java app which is getting data from a database.
Here is the applicationContext.xml
<bean id="Lookup" class="com.gd.test.Lookup"> <property name="AssetClassDao" ref="assetClass" /> </bean> <bean id="assetClass" class="com.gd.impl.AssetClassImpl"> <property name="dataSource" ref="dataSource" /> </bean> <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"> <property name="driverClassName" value="org.apache.commons.dbcp.BasicDataSource" /> <property name="url" value="jdbc:sqlserver://ip:port;databaseName=test" /> <property name="username" value="user" /> <property name="password" value="pass" /> </bean>
AssetClassDao.java
public interface AssetClassDao { public AssetClass getAssetDataById(int id); }
AssetClassImpl.java
public class AssetClassImpl implements AssetClassDao { private DataSource dataSource; AssetClass ac = new AssetClass(); @Override public AssetClass getAssetDataById(int id) { String sql = "select id, name from TABLE where id=" + String.valueOf(id); Connection conn = null; try { conn = dataSource.getConnection(); PreparedStatement ps = conn.prepareStatement(sql); ResultSet rs = ps.executeQuery(); while (rs.next()) { ac.setASSET_CLASS_ID(rs.getString("id")); ac.setASSET_CLASS_NAME(rs.getString("name")); } rs.close(); ps.close(); return ac; } catch (SQLException e) { e.printStackTrace(); } return ac; } public DataSource getDataSource() { return dataSource; } public void setDataSource(DataSource dataSource) { this.dataSource = dataSource; } }
Lookup.java
public class Lookup { private AssetClassDao assetClassDao; public void runNameLookup() throws IOException { AssetClass byOne = assetClassDao.getAssetDataById(5); System.out.println(byOne.toString()); } public AssetClassDao getAssetClassDao() { return assetClassDao; } public void setAssetClassDao(AssetClassDao assetClassDao) { this.assetClassDao = assetClassDao; } }
The query returns "5" as the ID and "Mortgage" as the NAME. For my test that I am writing with Mockito, how does it know which implementation to use?
My test:
public class TestLookup { @Mock private AssetClassDao acd; @Mock private Lookup al; @Mock private AssetClass ac; @Before public void setupMock(){ MockitoAnnotations.initMocks(this); acd = mock(AssetClassImpl.class); } @Test public void testDataById(){ when(acd.getAssetDataById(5)).thenReturn(ac); System.out.println(acd.getAssetDataById(5).getNAME()); } }
How do I test these values properly?!
Answer:
By writing the following statements you are creating a new object of class AssetClass
:
AssetClass ac = new AssetClass();
If you are using Spring then you should be injecting this as one of the dependencies as follows:
@Autowired private AssetClass ac;
You can now mock this dependency out by writing the following in your test class:
@Mock private AssetClass ac;
Also, you'll have to mock the other dependencies like DataSource
, Connection
etc. and do something like this:
@Mock private DataSource dataSource; @Mock private Connection conn; ... Mockito.when(dataSource.getConnection()).thenReturn(conn);
I hope this will provide you some essence of Mockito and how to use it.
Question:
I am trying to mock a DAO class that has a method which returns a list of a specific class.
private List<SpecificClass> getInfo(){ List<SpecificClass> returnInformation = dao.list(ParamOne, Param Two, SpecificClass.class); }
The dao mentioned in the above method refers to another class.
I begin by mocking that DAO class.
Mockito.mock(TheDaoClass.class);
and creating a mocked list
private @Mock List<SpecificClass> returnedList = new ArrayList<SpecificClass>();
Then I make call to that method
dao.list(ParamOne, Param Two, SpecificClass.class);
and specify what needs to be done when it is called
when(dao.list(ParameterOne, anyString(), SpecificClass.class)).thenReturn(returnedList);
When I do the above I get a null pointer exception. There can be two causes:
I understand the list is empty but all it is supposed is hold SpecificClass's five values but that shouldn't throw an error at this point.
I think object dao
is not getting mocked properly. I am only mocking the whole class Mockito.mock(TheDaoClass.class)
in order to mock any object asociated with that class. I think that it is not achieving the objective. how do I go about solving this problem? Any help is appreciated. Thanks.
Answer:
Make your mocked DAO object a property of your test class like so:
@Mock private TheDaoClass mockDaoClass;
Then, in your setUp()
method at the beginning of your test class call initMocks
:
@BeforeClass public void setUp() { MockitoAnnotations.initMocks(this); }
This should prevent the NullPointer
.
Additionally, I recommend that rather than mock the List
object (if you are mocking any Java library data type you are probably doing it wrong), you should create a list and populate it.
List<SpecificClass> list = new ArrayList<SpecificClass>(); list.add(new SpecificClass());
Then return the list from the mocked method.
when(mockDaoClass.list(anyString(), anyString(), SpecificClass.class)).thenReturn(list);
Question:
I have a Spring MVC application. It has Controller, Service and Dao. I would like to test only the Controller and Service by Mocking the DAO layer using Mockito.
My Controller class:
@Controller @RequestMapping(value="/audit") public class AuditController { @Autowired AuditService auditService; ... }
My Service class:
@Service public class AuditService { @Autowired AuditDao auditDao; .... }
My Test class:
@RunWith(SptringJUnit4ClassRunner.class) @ContextConfiguration(locations = {"/dispatcher-servlet.xml", "spring-context.xml"}) @WebAppConfiguration public class AuditControllerTest { private MockMvc mockMvc; @Mock AuditDao auditDao; @Autowired private WebApplicationContext webApplicationContext; @Before public void setUp() { MockitAnnotations.initMocks(this); mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build(); } @Test public void testGetAudit() { Mockito.when(auditDao.getAudit(Mockito.any(Long.class))).thenReturn(new Audit(1L)); mockMvc.perform(get("/audit/{id}", "1")).andExpect(status().isOk()); } }
PROBLEM: It performs the call fine by going through autowired controller and Service. However, from the Service the DAO calls are going to a real DAO not the Mocked DAO.
I understand that the DAO is autowired to the real Dao, however I am not sure how to replace that Dao with the Mock one from the Test.
Keeping the Dao in the controller and using @InjectMock to the controller works fine, but I want to keep the Dao in the Service and test only the controller and Service, but mock the Dao alone.
I suspect that this issue is to do with the contexts (web application context and the MockMvc context), however I am not sure how to resolve it.
Any help would be greatly appreciated. Thanks in advance.
Answer:
First I would suggest avoiding Autowired
fields and have you class explicitly expose their dependencies via constructor dependencies
Controller class:
@Controller @RequestMapping(value="/audit") public class AuditController { private final AuditService auditService; @Autowired public AuditController(AuditService auditService) { this.auditService = auditService } //... }
Service class:
@Service public class AuditService { private final AuditDao auditDao; @Autowired public AuditService(AuditDao auditDao) { this.auditDao = auditDao; } //.... }
I was thinking of something along the line of
@RunWith(SptringJUnit4ClassRunner.class) @ContextConfiguration(locations = {"/dispatcher-servlet.xml", "spring-context.xml"}) @WebAppConfiguration public class AuditControllerTest { private MockMvc mockMvc; @Mock AuditDao auditDao; @InjectMock AuditService auditService; @Before public void setUp() { MockitAnnotations.initMocks(this); AuditController controller = new AuditController (auditService); mockMvc = MockMvcBuilders.standaloneSetup(controller).build(); } @Test public void testGetAudit() { Mockito.when(auditDao.getAudit(Mockito.any(Long.class))).thenReturn(new Audit(1L)); mockMvc.perform(get("/audit/{id}", "1")).andExpect(status().isOk()); } }
But am uncertain if it will behave as expected when exercised.
Question:
I want to test my DAO methods using Mockito (and PowerMockito if needed), but I don't know how to do this. The biggest problem with calling static method (MySQLDAOFactory.getConnection() in MySQLStationDAO). Can you help me?
I obtain connection this way:
public class MySQLDAOFactory extends DAOFactory { public static Connection getConnection() throws DAOException { Connection con = null; try { con = getDataSource().getConnection(); } catch (SQLException e) { throw new DAOException(Messages.CANNOT_OBTAIN_CONNECTION, e); } return con; }
And here is a DAO method:
public class MySQLStationDAO implements StationDAO { @Override public List<Station> getAllStations() throws DAOException { List<Station> stations = new ArrayList<>(); Connection con = null; Statement stmt = null; ResultSet rs = null; try { con = MySQLDAOFactory.getConnection(); stmt = con.createStatement(); rs = stmt.executeQuery(MySQLQueries.SQL_GET_ALL_STATIONS); while (rs.next()) { stations.add(extractStation(rs)); } } catch (SQLException e) { throw new DAOException(Messages.CANNOT_OBTAIN_ALL_STATIONS, e); } finally { MySQLDAOFactory.close(con, stmt, rs); } return stations; }
Answer:
JUnit: use
@RunWith(PowerMockRunner.class)
at the class-level.TestNG: make your test class extend
PowerMockTestCase
.Use
@PrepareForTest(MySQLDAOFactory.class)
at the class-level in order to instruct PowerMock to prepare theMySQLDAOFactory
class for testing.Use
PowerMockito.mockStatic(MySQLDAOFactory.class)
in order to mock all methods ofMySQLDAOFactory
class.It is also possible to use partial mocking:
PowerMockito.stub(PowerMockito.method(MySQLDAOFactory.class, "getConnection")).toReturn(Mockito.mock(Connection.class));
Use something similar in order to stub
getConnection()
:Connection mockConnection = Mockito.mock(Connection.class); Mockito.when(MySQLDAOFactory.getConnection()).thenReturn(mockConnection);
Execute
getAllStations()
on a real instance ofMySQLStationDAO
, since you are testingMySQLStationDAO
class.If you want to verify that
getConnection()
method has been called, use something similar:PowerMockito.verifyStatic(); MySQLDAOFactory.getConnection();
However, please read Mockito.verify(T) javadoc for the reasons why it is recommended either to stub or to verify the invocation, not both.
In general, you may want to consult Mockito docs and PowerMockito docs for more information.
Full example that was created using JUnit 4.11, Mockito 1.9.5 and PowerMock (PowerMockito) 1.5.6 (please be careful with versions, since there is a lot of compatibility issues):
@RunWith(PowerMockRunner.class) @PrepareForTest(MySQLDAOFactory.class) public class MySQLDAOFactoryTest { private StationDAO stationDAO; @Mock private Connection mockConnection; @Mock private Statement mockStatement; @Mock private ResultSet mockResultSet; @Before public void setUp() { stationDAO = new MySQLStationDAO(); } @Test public void testGetAllStations_StatementCreated() throws DAOException, SQLException { // given PowerMockito.mockStatic(MySQLDAOFactory.class); Mockito.when(MySQLDAOFactory.getConnection()).thenReturn(mockConnection); Mockito.when(mockConnection.createStatement()).thenReturn(mockStatement); Mockito.when(mockStatement.executeQuery(anyString())).thenReturn(mockResultSet); // when stationDAO.getAllStations(); // then Mockito.verify(mockConnection).createStatement(); } }
What is next? Check that executeQuery()
method has been called with expected arguments? Test how SQLException
is handled? These are reasonable scenarios for unit testing, but what about integration testing? I would recommend DBUnit for this purpose. It puts your test database into a known state between test runs, and allows to verify a returned result against an expected XML dataset.
Question:
I'm just getting into testing of code. I have done unit tests before but haven't really isolated them. So they were more like integration test (indirectly). I want to give Mockito a try and I have added it to my Intellij IDE. But I have no idea of how to actually implement mocking at all. There are examples on their website but I just can't wrap my head around the concept of mocking. I know that one uses mocking to isolate the unit testing to ensure that the errors are in the unit itself and not in a dependency.
I wrote the following:
@Test public void testChangeMemberReturnsTrue() throws Exception { Member tempMem = new Member(); tempMem.setMemberFirstName("Swagrid"); tempMem.setMemberLastName("McLovin"); tempMem.setMemberID("SM666"); SQLDUMMY.saveMember(tempMem); //Save member to dummy DB. Member checkMem = new Member(); ArrayList<Member> memArr = SQLDUMMY.getAllMembers(); for (Member m : memArr) { // Look through all saved members if (m.equals(tempMem)) { // If match, save to checkMem checkMem = m; } } assertTrue(tempMem.equals(checkMem)); // Make sure they are really equal. String newfirstname = "Darius"; String newlastname = "DunkMaster"; assertTrue(memhandling.changeMember(tempMem, newfirstname, newlastname)); }
And here is the actual method:
public boolean changeMember(Member mem, String n1, String n2) { try { ArrayList<Member> memArr = SQLDUMMY.getAllMembers(); for (Member m : memArr) { if (m.equals(mem)) { m.setMemberFirstName(n1); m.setMemberLastName(n2); m.setMemberID(ensureUniqueID(m, m.getMemberID())); //Just a method call to another method in the same class to ensure ID uniqueness. return true; } else { return false; } } } catch (Exception e) { System.out.println("Error4."); } return false; }
I'd like to mock the SQLDUMMY (Which I created just to see if my tests would pass at all, which they do.) The SQLDUMMY class looks like this:
public class SQLDUMMY { private static ArrayList<Member> memberList = new ArrayList<>(); private static ArrayList<Ship> shipList = new ArrayList<>(); public static ArrayList<Member> getAllMembers() { return memberList; } public static void saveMember(Member m) { memberList.add(m); } public static void deleteMember(Member memIn) { memberList.remove(memIn); } public static void saveShip(Ship newShip) { shipList.add(newShip); } public static ArrayList<Ship> getAllShips() { return shipList; } public static void deleteShip(Ship s) { shipList.remove(s); }
}
It basically just consists of getters and add/remove for the ArrayLists that act as a contemporary DB storage.
Summary: How can I mock the SQLDUMMY class (DAO), so it is no longer a dependency for the Unit tests?
Answer:
You need to read on how Mockito works. The basic idea is that it extends you class and and overrides all methods and allows you to return what ever you want it too.
Syntax is :
SQLDummy sqlDummy = Mockito.mock(SQLDummy.class); Mockito.when(sqlDummy.getAllShips()).thenReturn(new ArrayList< Ship >())
Question:
I'm new in unit test, and I'm trying to write some tests for my DAO's. I have followed some tutorials/answers here, but most of them don't apply to my DAO's.
I get this warning when I run the test org.mockito.exceptions.verification.WantedButNotInvoked: Wanted but not invoked: mockConn.prepareStatement();
What is wrong?
private ApprovalConditionDAO approvalConditionDAO; @Mock DataSource mockDataSource; @Mock Connection mockConn; @Mock PreparedStatement mockPreparedStmnt; @Mock CallableStatement cs; @Mock ResultSet mockResultSet; @Before public void setUp() throws SQLException { approvalConditionDAO = new ApprovalConditionDAO(); when(mockDataSource.getConnection()).thenReturn(mockConn); when(mockDataSource.getConnection(anyString(), anyString())).thenReturn(mockConn); when(mockConn.prepareStatement(anyString(), anyInt())).thenReturn(mockPreparedStmnt); doNothing().when(mockConn).commit(); doNothing().when(mockPreparedStmnt).setString(anyInt(), anyString()); when(mockPreparedStmnt.execute()).thenReturn(Boolean.TRUE); when(mockPreparedStmnt.getGeneratedKeys()).thenReturn(mockResultSet); when(mockResultSet.next()).thenReturn(Boolean.TRUE, Boolean.FALSE); } @Test public void testCreateWithNoExceptions() throws SQLException { ArrayList<ApprovalConditionBean> actualValues = approvalConditionDAO.getAllApprovalCondition(); //verify and assert verify(mockConn, times(1)).prepareStatement(anyString()); verify(mockPreparedStmnt, times(1)).execute(); verify(mockConn, times(1)).commit(); verify(mockResultSet, times(2)).next(); verify(mockResultSet, times(1)).getString("ID"); verify(mockResultSet, times(1)).getString("EIT_CODE"); verify(mockResultSet, times(1)).getString("FRIST_KEY_TYPE"); verify(mockResultSet, times(1)).getString("FRIST_KEY_VALUE"); verify(mockResultSet, times(1)).getString("FRIST_EIT_SEGMENT"); verify(mockResultSet, times(1)).getString("OPERATION"); verify(mockResultSet, times(1)).getString("SECOND_KEY_TYPE"); verify(mockResultSet, times(1)).getString("SECOND_KEY_VALUE"); verify(mockResultSet, times(1)).getString("SECOND_EIT_SEGMENT"); verify(mockResultSet, times(1)).getString("APPROVAL_CODE"); }
And this is the Dao that I want to test it.
public class ApprovalConditionDAO extends AppsproConnection { Connection connection; PreparedStatement ps; CallableStatement cs; ResultSet rs; RestHelper rh = new RestHelper(); public ArrayList<ApprovalConditionBean> getAllApprovalCondition() { ArrayList<ApprovalConditionBean> approvalConditionList = new ArrayList<ApprovalConditionBean>(); try { connection = AppsproConnection.getConnection(); String query = "SELECT * FROM "+" "+getSchema_Name()+".XXX_APPROVAL_CONDITION"; ps = connection.prepareStatement(query); rs = ps.executeQuery(); while (rs.next()) { ApprovalConditionBean approvalConditionBean = new ApprovalConditionBean(); approvalConditionBean.setId(rs.getString("ID")); approvalConditionBean.setEitCode(rs.getString("EIT_CODE")); approvalConditionBean.setFirstKeyType(rs.getString("FRIST_KEY_TYPE")); approvalConditionBean.setFirstKeyValue(rs.getString("FRIST_KEY_VALUE")); approvalConditionBean.setFirstEitSegment(rs.getString("FRIST_EIT_SEGMENT")); approvalConditionBean.setOperation(rs.getString("OPERATION")); approvalConditionBean.setSecondKeyType(rs.getString("SECOND_KEY_TYPE")); approvalConditionBean.setSecondKeyValue(rs.getString("SECOND_KEY_VALUE")); approvalConditionBean.setSecondEitSegment(rs.getString("SECOND_EIT_SEGMENT")); approvalConditionBean.setApprovalCode(rs.getString("APPROVAL_CODE")); approvalConditionList.add(approvalConditionBean); } } catch (Exception e) { //("Error: "); e.printStackTrace(); } finally { closeResources(connection, ps, rs); } return approvalConditionList; }
And this as my AppsproConnection Calss
public static Connection getConnection(boolean commit) { if (CommonConfigReader.getValue("CONNECTION_TYPE").equalsIgnoreCase("JDBC")) { return getJDBCConnection(commit); } else { return getDSConnection(commit); } } public static Connection getConnection() { if (CommonConfigReader.getValue("CONNECTION_TYPE").equalsIgnoreCase("JDBC")) { return getJDBCConnection(); } else { return getDSConnection(); } }
Answer:
You didn't call the method you wanted to test from the test method. You don't event have a test object to do so.
class TestClass { private MyDao underTest; @Before public void setUp() throws SQLException { underTest = new MyDao(); // mocking things... } }
And using this test object you have to call the method you actually want to test from a test method.
@Test public void testCreateWithNoExceptions() throws SQLException { // ... ArrayList<ApprovalConditionBean> actualValues = underTest.getAllApprovalCondition(); // assertions }
If you cannot manipulate how you get the connection from a static class then you can refactor your method to get a connection from another method in the same class.
public ArrayList<ApprovalConditionBean> getAllApprovalCondition() { // ... connection = getConnection(); // ... } Connection getConnection() { return AppsproConnection.getConnection(); }
If you are using like this you can instantiate the test object in a way that you can manage what kind of Connection is returned for tests.
@Before public void setUp() throws SQLException { when(mockConn.prepareStatement(anyString(), anyInt())).thenReturn(mockPreparedStmnt); doNothing().when(mockConn).commit(); doNothing().when(mockPreparedStmnt).setString(anyInt(), anyString()); when(mockPreparedStmnt.execute()).thenReturn(Boolean.TRUE); when(mockPreparedStmnt.getGeneratedKeys()).thenReturn(mockResultSet); when(mockResultSet.next()).thenReturn(Boolean.TRUE, Boolean.FALSE); underTest = new MyDao(){ @Override public Connection getConnection() { return mockConn; } }; }
We are returning the mocked connection from getConnection
. This method is called from the getAllApprovalCondition
method. In production it is still providing connection through AppsproConnection
.
Question:
I am not able to mock Dao method in spring boot. Please let me know what I am doing wrong in below code. I tried using SpringJUnit4ClassRunner and mock the Dao method. But still, it's going into the Dao method instead of returning the mock value. I also tried with MockitoJUnitRunner but that time not able to call the service method as its getting null value.
@RestController public class HomeController { @Autowired HomeSeriveInterface service; @Autowired HomeDaoImpl homeDao; @GetMapping(value="/getData") public String Data() { System.out.println("Inside Controller"); List < Map < String, Object >> rows = service.getData(); return "Hi Yogita" + rows; } } @Service public class HomeService implements HomeSeriveInterface{ @Autowired HomeDao dao; @Override public List<Map<String, Object>> getData() { System.out.println("Inside Service"); return dao.getData(); } } @Repository public class HomeDaoImpl implements HomeDao{ @Autowired @Qualifier("jdbcTemplate1") private JdbcTemplate jdbcTemplate; @Override public List < Map < String, Object >> getData() { System.out.println("Inside Dao"); List < Map < String, Object >> rows = jdbcTemplate.queryForList("SELECT * FROM COURCES"); return rows; } } @RunWith(SpringJUnit4ClassRunner.class) @SpringBootTest public class CcdWebApplicationTests { @InjectMocks @Autowired HomeController homeController; @Mock HomeDao homeDao; @Before public void init() { MockitoAnnotations.initMocks(this); } @Test public void getDataTest() { System.out.println("testing *******"); List < Map < String, Object >> data = null; Mockito.when(homeDao.getData()) .thenReturn(data); System.out.println("2nd *"); String data2 = homeController.Data(); System.out.println(data2); } }
Answer:
You don't need @InjectMocks
and use @MockBean
instead of @Mock
:
@Autowired HomeController homeController; @MockBean HomeDao homeDao;
You also do not need this part:
@Before public void init() { MockitoAnnotations.initMocks(this); }
Question:
I'm using Mockito for testing my API Service REST, i'm using Spring Framework 4.1.4.RELEASE and Mockito 1.9.5.
I have a multi-brand system for access to unique DAOImpl (With unique for each brand @PersistenceContext(unitname = "emX"), where "X" it's brand char) , each brand extends from abstract DaoBase class (who implemements an interface called Dao) and i access from Service class obtaining the component via:
applicationContext.getBean(qualifier.concat(brand.name()), clazz)
(Where qualifier.concat(brand.name()) its = "DaoA" for example)
This is the structure:
- es.app.service
- ServiceClass.java calls DaoFactory to get Impl.
- es.app.dao
- Dao.java
- DaoBase.java implements Dao
- DaoFactory.java
- es.app.dao.impl
- DaoAImpl.java extends DaoBase @Repository("DaoA")
- DaoBImpl.java extends DaoBase @Repository("DaoB")
- DaoCImpl.java extends DaoBase @Repository("DaoC")
- DaoDImpl.java extends DaoBase @Repository("DaoD")
Then i have a test class on Test Packages
- es.app.service
ServiceClassTest.java
I put a little code for each class here:
DaoFactory.java
@Component public class DaoFactory implements Serializable, ApplicationContextAware{ private ApplicationContext ctx; private static final long serialVersionUID = 1L; private static final Logger LOGGER = LoggerFactory.getLogger(DaoFactory.class); public Dao getInstance(GroupBrand brand){ switch(brand){ case A: case B: case C: case D: return (Dao)getComponent("Dao",Dao.class, brand); default: break; } throw new IllegalArgumentException("Unsupported brand ".concat(brand.name())); } private Object getComponent(String qualifier, Class<?> clazz, GroupBrand brand){ Object instance = ctx.getBean(qualifier.concat(brand.name()), clazz); if(Utils.isNull(instance)){ throw new IllegalArgumentException("Unkown business bean with Qualifier: ".concat(qualifier.concat(brand.name())).concat("type: ").concat(clazz.getName())); } LOGGER.debug("DAO retrived: " + qualifier.concat(brand.name()) +" class: " + clazz.getName()); return instance; } @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { this.ctx = applicationContext; } }
DaoBase.java
public abstract class DaoBase implements Dao { protected abstract EntityManager getEntityManager(); private static final String EMPTY = ""; private static final Logger LOGGER = LoggerFactory.getLogger(DaoBase.class); @Override public Boolean findAvailability(GroupBrand marca, String code) { EntityManager em = getEntityManager(); Query query = em.createNamedQuery("Conn.isAvailability"); query.setParameter(1, code); query.setParameter(2, marca.toCharCode()); try{ String value = (String)query.getSingleResult(); if(value.equalsIgnoreCase("S")){ return true; }else{ return false; } }catch(Exception ex){ return Boolean.FALSE; } } }
DaoAImpl.java
@Repository("DaoA") public class DaoAImpl extends DaoBase { @PersistenceContext(unitName = "emA") private EntityManager em; @Override @Transactional("A") public Boolean findAvailability(GroupBrand marca, String code) { return super.findAvailability(marca, code); } }
ServiceClass.java
@Override public boolean isAvailable(GroupBrand brand, String code){ Boolean available = getDMSQisAvailability(brand, code); return available; } protected Boolean isAvailability(GroupBrand marca, String kvps){ boolean value = daoFactory.getInstance(marca).findDMSQisAvailability(marca, code); return value; }
ServiceClassTest.java
@InjectMocks @Autowired @Qualifier("serviceClass") private ServiceClass srv; @Autowired @Qualifier("DaoFactory") protected DaoFactory daoFactory; @Mock protected Dao dao; @Override public void mockBehaivors() throws ResourceException, ResourceNotFoundException, ApiException { MockitoAnnotations.initMocks(this); dao = daoFactory.getInstance(marca); when(dao.findAvailability(any(GroupBrand.class), any(String.class))).thenReturn(Boolean.TRUE); } @Test public void isAvailableTest() throws ResourceException, Exception{ Boolean available = srv.isAvailable(GroupBrand.A, "CODE"); }
I need to coverage ServiceClass.java class but i can't mock Dao calls from this Test class always do real call and don't return what i defined on "when", other tests works but are not using dao access.
Anyone can help me?
(Apologies for my poor english)..
Regards,
Answer:
At least i found a solution of my problem,
I haved to mock DaoFactory when calls getInstance() i return a mock of Dao class.
Class test it like this:
@InjectMocks @Autowired @Qualifier("serviceClass") private ServiceClass srv; @Mock @Autowired @Qualifier("DaoA") protected Dao dao; @Mock @Autowired @Qualifier("DaoFactory") protected DaoFactory daoFactory; @Override public void mockBehaivors() throws ResourceException, ResourceNotFoundException, ApiException { MockitoAnnotations.initMocks(this); when(daoFactory.getInstance(GroupBrand.A)).thenReturn(dao); when(dao.findAvailability(any(GroupBrand.class), any(String.class))).thenReturn(Boolean.TRUE); } @Test public void isAvailableTest() throws ResourceException, Exception{ Boolean available = srv.isAvailable(GroupBrand.A, "CODE"); }
And it's works!!!!
Question:
I'm trying to write some tests for my DAO's. I have followed some tutorials/answers here, but most of them don't apply to my DAO's.
Example code: trying to get the elections from the database based on the given selector (< or >).
public class AdminDaoImpl extends DaoImpl implements AdminDao { private final Logger LOGGER = Logger.getLogger(getClass().getName()); @Override public ElectionListResponse getElections(char selector) { ElectionListResponse electionListResponse = new ElectionListResponse(); String query = NamedQueries.GET_ELECTIONS_BEGIN + selector + NamedQueries.GET_ELECTIONS_END; try { con = sqlConnection.getConnection(); stmt = con.prepareStatement(query); rs = stmt.executeQuery(); DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm"); while (rs.next()) { Election election = new Election(); election.setElectionID(rs.getInt("id")); election.setElectionName(rs.getString("name")); election.setStartDate(df.format(rs.getDate("startDate"))); election.setEndDate(df.format(rs.getDate("endDate"))); electionListResponse.addElection(election); } return electionListResponse; } catch (SQLException e) { LOGGER.log(Level.SEVERE, "Cant get elections. ", e); } finally { closeConnection(); } return null; }
This is the DAO that the code above extends:
public abstract class DaoImpl implements Dao { private final Logger LOGGER = Logger.getLogger(getClass().getName()); @Inject public SQLConnection sqlConnection; public Connection con; public PreparedStatement stmt; public ResultSet rs; public void closeConnection() { try { if (con != null) con.close(); if (stmt != null) stmt.close(); if (rs != null) con.close(); } catch (SQLException e) { LOGGER.log(Level.SEVERE, "Can't close connection with database. ", e); } } }
I have tried to apply some code that I found online and this is what I currently have:
@RunWith(MockitoJUnitRunner.class) public class AdminDaoImplTest { @Mock DataSource mockDataSource; @Mock Connection mockConn; @Mock PreparedStatement mockPreparedStmnt; @Mock ResultSet mockResultSet; @BeforeClass public static void setUpClass() throws Exception { } @AfterClass public static void tearDownClass() { } @Before public void setUp() throws SQLException { when(mockDataSource.getConnection()).thenReturn(mockConn); when(mockDataSource.getConnection(anyString(), anyString())).thenReturn(mockConn); doNothing().when(mockConn).commit(); when(mockConn.prepareStatement(anyString(), anyInt())).thenReturn(mockPreparedStmnt); doNothing().when(mockPreparedStmnt).setString(anyInt(), anyString()); when(mockPreparedStmnt.executeQuery()).thenReturn(mockResultSet); when(mockResultSet.next()).thenReturn(Boolean.TRUE, Boolean.FALSE); } @After public void tearDown() { } @Test public void testCreateWithNoExceptions() throws SQLException { ElectionListResponse electionListResponse = new ElectionListResponse(); AdminDaoImpl instance = new AdminDaoImpl(); instance.getElections('>' ); //verify and assert verify(mockConn, times(1)).prepareStatement(anyString(), anyInt()); verify(mockPreparedStmnt, times(1)).execute(); verify(mockConn, times(1)).commit(); verify(mockResultSet, times(2)).next(); verify(mockResultSet, times(1)).getInt("id"); verify(mockResultSet, times(1)).getString("name"); verify(mockResultSet, times(1)).getDate("startDate"); verify(mockResultSet, times(1)).getDate("endDate"); } }
How should I test it ? Would you please produce some code samples? Thanks in advance!
NullPointer:
java.lang.NullPointerException at org.han.ica.oose.sneeuwklokje.database.admin.AdminDaoImpl.getElections(AdminDaoImpl.java:28) at org.han.ica.oose.sneeuwklokje.database.admin.AdminDaoImplTest.testGetElectionsNoExceptions(AdminDaoImplTest.java:77) 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:50) at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12) at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47) at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17) at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26) at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27) at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57) at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290) at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71) at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288) at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58) at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268) at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26) at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27) at org.junit.runners.ParentRunner.run(ParentRunner.java:363) 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:137) 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 should add to the test the following field:
@InjectMocks private AdminDaoImpl
this will inject the mocks in your class, allowing you to test.
The NullPointerException you get can be fixed in this way (in test class):
@Mock private SQLConnection mockSqlConnection;
in setup method add this:
when(mockSqlConnection.getConnection()).thenReturn(mockConn);