JDBC Mocking KeyHolder - java

Trying Mock method that have KeyHolder. But keyHolder is null. Method is working. Please help. Need to modify test some how.
#Autowired
private KeyHolderFactory factory;
#Override
public Integer createRss(String url) throws Exception {
KeyHolder holder = factory.newKeyHolder();
try {
jdbcTemplate.update(new PreparedStatementCreator() {
#Override
public PreparedStatement createPreparedStatement(Connection connection) throws SQLException {
PreparedStatement ps = connection.prepareStatement(CREATE_RSS, Statement.RETURN_GENERATED_KEYS);
ps.setString(1, url);
return ps;
}
}, holder);
} catch (DataAccessException e) {
throw new Exception("Rss already exist");
}
return holder.getKey().intValue();
}
This is my test body.Trying to mock keyHolder but it does not work.
public class RSSDaoImplTest {
#InjectMocks
private RSSDaoImpl target;
#Mock
private KeyHolder keyHolder;
#Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
this.mockDS = Mockito.mock(DataSource.class);
this.mockJT = Mockito.mock(JdbcTemplate.class);
target = new RSSDaoImpl();
target.setJdbcTemplate(mockDS);
target.setJdbcTemplate(mockJT);
}
#Test
public void testCreateRss() throws Exception {
Mockito.when(mockJT.update(Mockito.any(PreparedStatementCreator.class), Mockito.any(KeyHolder.class)))
.thenReturn(1);
Mockito.doReturn(1).when(keyHolder).getKey().intValue();
int actual = target.createRss("test");
assertEquals(1, actual);
}
}
Could not find any solution on stackoverflow. Thank you in advance

You can try the following code:
Mockito.when(keyHolderFactoryMock.newKeyHolder()).thenReturn(keyHolderMock);
Mockito.when(keyHolderMock.getKey()).thenReturn(1);
Mockito.when(jdbcTemplate.update(Mockito.any(PreparedStatementCreator.class), Mockito.any(KeyHolder.class))).thenReturn(1);

Related

mocking a method with a dynamic datasource

I need to test this method but I don't know how can I test without connecting to the db on the server.
public List<String> searchQuery(String key) {
List<String> resultList = null;
try {
this.createConnection(CheckDataServlet.getKey(Integer.parseInt(key)).getConnection().getName());
stmt = conn.prepareStatement(CheckDataServlet.getKey(Integer.parseInt(key)).getSelect().trim());
rs = stmt.executeQuery();
resultList = this.getValues(rs);
} catch ( SQLException e) {
Archicon.getLogger().error("ValidationData.searchQuery error: "+e);
}finally {
this.closeConnection("searchQuery",conn,stmt,rs);
}
if (resultList == null) {
resultList = new ArrayList<>();
}
return resultList;
}
public void createConnection(String key){
try {
ds = (DataSource) Archicon.getResource("jdbc/"+key);
conn = ds.getConnection();
} catch (SQLException | NamingException e) {
throw new RuntimeException(e);
}
}
I tried testing with Mockito but always give me this error because the datasource is null:
java.lang.NullPointerException
at it.sisal.archicon.model.valor.ValidationData.createConnection(ValidationData.java:157)
at it.sisal.archicon.model.valor.ValidationData.searchQuery(ValidationData.java:23)
at it.sisal.archicon.model.valor.AwpSapNewRepositoryTest.searchQuery(AwpSapNewRepositoryTest.java:95)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
I tried to build this test class:
#RunWith(MockitoJUnitRunner.class)
public class AwpSapNewRepositoryTest {
#Mock
private ValidationData validationData;
#Before
public void setup() throws SQLException {
MockitoAnnotations.initMocks(this);
try (final MockedStatic<Archicon> archicon= Mockito.mockStatic(Archicon.class)) {
DataSource ds = mock(DataSource.class);
archicon.when(() -> Archicon.getResource(any())).thenReturn(ds);
}
#Test
public void searchQuery() throws NamingException {
// System.setProperty("jboss.server.config.dir","C:\\Program Files\\wildfly-18.0.0.Final\\standalone\\configuration\\archicon");
Archicon.setConfigPath("C:\\Program Files\\wildfly-18.0.0.Final\\standalone\\configuration\\archicon");
when(validationData.searchQuery("11")).thenReturn(new ArrayList<>(List.of("Name, 99","Stuff, 99")));
validationData = new ValidationData();
assertEquals(true,validationData.searchQuery("11").size()>0);
}
Does anybody know a good way to test this method?
You could mock the static method of the Archicon class with mockito to return a mock of DataSource:
try (final MockedSatic<Archicon> archicon= Mockito.mockStatic(Archicon.class)) {
DataSource ds = mock(DataSource.class);
archicon.when(() -> Archicon.getResource(any())).thenReturn(ds);
}

Mockito doAnswer()

Can I somehow use doAnswer() when an exception is thrown?
I'm using this in my integration test to get method invocations and the test in configured the #RabbitListenerTest...
#RunWith(SpringRunner.class)
#SpringBootTest
public class MyIT {
#Autowired
private RabbitTemplate rabbitTemplate;
#Autowired
private MyRabbitListener myRabbitListener;
#Autowired
private RabbitListenerTestHarness harness;
#Test
public void testListener() throws InterruptedException {
MyRabbitListener myRabbitListener = this.harness.getSpy("event");
assertNotNull(myRabbitListener);
final String message = "Test Message";
LatchCountDownAndCallRealMethodAnswer answer = new LatchCountDownAndCallRealMethodAnswer(1);
doAnswer(answer).when(myRabbitListener).event(message);
rabbitTemplate.convertAndSend("exchange", "key", message);
assertTrue(answer.getLatch().await(20, TimeUnit.SECONDS));
verify(myRabbitListener).messageReceiver(message);
}
#Configuration
#RabbitListenerTest
public static class Config {
#Bean
public MyRabbitListener myRabbitListener(){
return new MyRabbitListener();
}
}
}
It works ok but when I introduce an Exception being thrown, It doesn't i.e
This works
#RabbitListener(id = "event", queues = "queue-name")
public void event(String message) {
log.info("received message > " + message);
}
This doesn't
#RabbitListener(id = "event", queues = "queue-name")
public void event(String message) {
log.info("received message > " + message);
throw new ImmediateAcknowledgeAmqpException("Invalid message, " + message);
}
Any help appreciated
The LatchCountDownAndCallRealMethodAnswer is very basic
#Override
public Void answer(InvocationOnMock invocation) throws Throwable {
invocation.callRealMethod();
this.latch.countDown();
return null;
}
You can copy it to a new class and change it to something like
private volatile Exception exeption;
#Override
public Void answer(InvocationOnMock invocation) throws Throwable {
try {
invocation.callRealMethod();
}
catch (RuntimeException e) {
this.exception = e;
throw e;
}
finally {
this.latch.countDown();
}
return null;
}
public Exception getException() {
return this.exception;
}
then
assertTrue(answer.getLatch().await(20, TimeUnit.SECONDS));
assertThat(answer.getException(), isInstanceOf(ImmediateAcknowledgeAmqpException.class));
Please open a github issue; the framework should support this out-of-the-box.

How do I test DAO using Mockito?

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();
}
}
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.

DBunit - DbAssertionFailedError

Getting frustrated with DBUnit :( Anyone know why I would get dbAssertionFailedError driverClass is null for the below please? dbunitData.xml contains the test data with one row. I know that the connection to the database is fine but the error seems to be triggered by the assertequals.
public class ExtendDBTestCaseTest extends DBTestCase
{
public static final String TABLE_LOGIN = "salarydetails";
private FlatXmlDataSet loadedDataSet;
private SalaryCalculation salaryCalculation;
#SuppressWarnings("deprecation")
protected IDataSet getDataSet() throws Exception
{
loadedDataSet = new FlatXmlDataSet(this.getClass().getClassLoader()
.getResourceAsStream("dbunitData.xml"));
return loadedDataSet;
}
protected void setUp() throws Exception
{
setUpDatabase();
}
#SuppressWarnings("deprecation")
private void setUpDatabase() throws Exception
{
Class.forName("com.mysql.jdbc.Driver");
Connection jdbcConnection = DriverManager.getConnection(
"jdbc:mysql://localhost:3306/salary", "someUser", "somePass");
IDatabaseConnection connection = new DatabaseConnection(jdbcConnection);
IDataSet dataSet = getDataSet();
try
{
getSetUpOperation().execute(connection, dataSet);
}
finally
{
connection.close();
}
}
protected DatabaseOperation getSetUpOperation() throws Exception{
return DatabaseOperation.REFRESH;
}
public void testCalculatorNeg() throws Exception
{
salaryCalculation = new SalaryCalculation();
int salary = salaryCalculation.calculator("12345");
assertEquals(0, salary);
}
}
Frustratingly I answered my own question after more trial and error. Just needed to add a teardown method with loadedDataSet.endDataSet(); and now works fine!

Cannot find datasource in JUnit tests

I have this simple CDI bean which displays content into JSF page:
#Named("ZonesController")
#ViewScoped
public class Zones implements Serializable
{
#Resource(name = "jdbc/Oracle")
private DataSource ds;
...........
public int countDBRowNum() throws Exception
{
String SqlStatement = null;
if (ds == null)
{
throw new SQLException();
}
Connection conn = ds.getConnection();
if (conn == null)
{
throw new SQLException();
}
PreparedStatement ps = null;
ResultSet resultSet = null;
int count = 0;
try
{
conn.setAutoCommit(false);
boolean committed = false;
try
{
SqlStatement = "SELECT COUNT(1) FROM component x, componentstats y WHERE x.componentstatsid = y.componentstatsid AND y.componenttypeid = 1100";
ps = conn.prepareStatement(SqlStatement);
resultSet = ps.executeQuery();
if (resultSet.next())
{
count = resultSet.getInt(1);
}
conn.commit();
committed = true;
}
finally
{
if (!committed)
{
conn.rollback();
}
}
}
finally
{
ps.close();
conn.close();
}
// Returns total rows in table.
return count;
}
.............
}
I created this JUnit test case which calls the Java method:
public class ZonesTest
{
#BeforeClass
public static void setUpClass() throws Exception
{
try
{
// Create initial context
System.setProperty(Context.INITIAL_CONTEXT_FACTORY,
"org.apache.naming.java.javaURLContextFactory");
System.setProperty(Context.URL_PKG_PREFIXES,
"org.apache.naming");
InitialContext ic = new InitialContext();
ic.createSubcontext("java:");
ic.createSubcontext("java:/comp");
ic.createSubcontext("java:/comp/env");
ic.createSubcontext("java:/comp/env/jdbc");
// Construct DataSource
OracleConnectionPoolDataSource ds = new OracleConnectionPoolDataSource();
ds.setURL("jdbc:oracle:thin:#192.168.1.104:1521:oracle");
ds.setUser("admin");
ds.setPassword("qwerty");
ic.bind("java:/comp/env/jdbc/oracle", ds);
}
catch (NamingException ex)
{
//Logger.getLogger(MyDAOTest.class.getName()).log(Level.SEVERE, null, ex);
}
}
#Test
public void testCountDBRowNum() throws Exception
{
Zones instance = new Zones();
int rows = instance.countDBRowNum();
System.out.println(rows);
}
}
I get error at these lines:
if (ds == null)
{
throw new SQLException();
}
How I can solve this problem? I want to use the datasource from the JUnit test during the testing. Can I somehow use the JUnit datasource?
You can make DataSource ds a JavaBean property and set its value on your JUnit test. This way you hide the complexity of the JNDI binding and focus your tests only on the business logic.
Your controller:
#Named("ZonesController")
#ViewScoped
public class Zones implements Serializable
{
#Resource(name = "jdbc/Oracle")
private DataSource ds;
public void setDs(DataSource ds){this.ds=ds;}
public DataSource getDs(){return ds;}
...
}
And you test class:
public class ZonesTest
{
private static OracleConnectionPoolDataSource ds;
#BeforeClass
public static void setUpClass() throws Exception
{
try
{
// Construct DataSource
ds = new OracleConnectionPoolDataSource();
ds.setURL("jdbc:oracle:thin:#192.168.1.104:1521:oracle");
ds.setUser("admin");
ds.setPassword("qwerty");
}
catch (NamingException ex)
{
//Logger.getLogger(MyDAOTest.class.getName()).log(Level.SEVERE, null, ex);
}
}
#Test
public void testCountDBRowNum() throws Exception
{
Zones instance = new Zones();
instance.setDs(ds);
int rows = instance.countDBRowNum();
System.out.println(rows);
}
}
As a side note, following the MVC design pattern I would even decouple the controller business logic from the database connection, so no valid connection is needed to execute the unit tests and your focus is entirely on the behavior of your controller.
If you are using Spring and want to use all Spring beans within your JUnit class you can always use the #RunWith JUnit annotation.
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration
public class ZonesTest
{
#Autowire
Zones zones;
// your BeforeClass method here
#Test
public void testCountDBRowNum() throws Exception
{
int rows = zones.countDBRowNum();
System.out.println(rows);
}
}

Categories