Mocking Result Set using mockito - java

I have a static class which has this method:
public static Connection getDbConnection(String tenant, String product) {
Connection connection = null;
try {
Map<String,Map<String,String >> databaseConnectionTable = PropertyUtil.getInstance().getDatabaseConnectionTable();
Map<String,String> properties = getHighestPrecedenceMap(databaseConnectionTable,tenant,product);
if (properties!=null) {
Class.forName(properties.get("db.driver"));
connection = DriverManager.getConnection(
properties.get("db.url"),
properties.get("db.user"),
properties.get("db.password"));
}
} catch (ClassNotFoundException e) {
LOGGER.error("Message",e);
} catch (SQLException e) {
LOGGER.error("Message:",e);
}
return connection;
}
Then I have another class which has a method for fetching the resultset given a SQL Query String, this method calls the above method, below is the source:
public static ResultSet getResultSetFromSql(String sql,String tenant,String product) {
Connection connection = null;
PreparedStatement statement = null;
ResultSet rs = null;
try {
if(product!=null)
connection = SqlConnectionUtil.getDbConnection(tenant,product);
RccSqlParameterMap parameterMap = RccSqlParameterMap.getParameterMap();
if(connection!=null) {
if (parameterMap.getSqlParameters().entrySet().size() > 0)
sql = parameterMap.SqlMessageFormat(sql);
else
LOGGER.error("Parameter map isn't set please initialize it");
LOGGER.info("Executing SQL: " + sql);
statement = connection.prepareStatement(sql, ResultSet.TYPE_FORWARD_ONLY,
ResultSet.CONCUR_READ_ONLY);
if (!statement.execute()) {
LOGGER.error("No results found for statement!");
return null;
}
rs = statement.getResultSet();
}else{
LOGGER.error("Coudn't create Connection Object");
}
} catch (SQLException e) {
LOGGER.error("Message", e);
}
return rs;
}
I need to write unit tests for testing these, to have an in memory implementation I am able to mock the result set, by reading the rows from files, so when I instantiate the result set mocker and do getResultSet() I get the result set object, the problem I am facing is integrating this mocker with the above methods. Please suggest a way to do this.

You can specify mock data right in the code of test case, there's no need to read something from the file system.
With Mockito you can make methods of the objects to return whatever you want:
// Initialize the object to be returned
ResultSet desiredResultSet = ...;
// After doing this you can mock methods of statement object
statement = Mockito.mock(PreparedStatement.class);
// Whenever you call statement.getResultSet(), it will return desiredResultSet
Mockito.doReturn(desiredResultSet).when(statement).getResultSet();
The only thing you need to change in your code to use this mechanism is to make Connection available to your test code. So that you can mock it's method that returns PreparedStatement the same way like I've demonstrated above.
In overall, I'd recommend you to split your methods to a bunch of smaller ones - right now they have too many things going on for just one method. This will also make your code much easier to unit test and mock.

With your current implementation it's impossible to mock connection object, since Mockito unable to mock static calls, that is possible with PowerMockito. There is possible solution (feel free to change test logic, it's just a worked skeleton with mocks for you)
import static org.junit.Assert.assertEquals;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.powermock.modules.junit4.PowerMockRunner;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import java.util.Map;
import java.util.HashMap;
#RunWith(PowerMockRunner.class)
#PrepareForTest({ SqlConnectionUtil.class, RccSqlParameterMap.class })
public class TestQueryRunner {
#Test
public void testGetResultSetFromSql() throws SQLException {
ResultSet rs = mock(ResultSet.class);
when(rs.getString(eq("foo"))).thenReturn("This is mocked value");
PreparedStatement stmt = mock(PreparedStatement.class);
when(stmt.getResultSet()).thenReturn(rs);
when(stmt.execute()).thenReturn(true);
Connection connection = mock(Connection.class);
when(connection.prepareStatement(anyString(), anyInt(), anyInt()))
.thenReturn(stmt);
PowerMockito.mockStatic(SqlConnectionUtil.class);
PowerMockito.when(SqlConnectionUtil.getDbConnection(anyString(), anyString()))
.thenReturn(connection);
Map<String, String> sqlParams = new HashMap<>();
sqlParams.put("param1", "value1");
RccSqlParameterMap paramMap = mock(RccSqlParameterMap.class);
when(paramMap.getSqlParameters()).thenReturn(sqlParams);
PowerMockito.mockStatic(RccSqlParameterMap.class);
PowerMockito.when(RccSqlParameterMap.getParameterMap()).thenReturn(paramMap);
ResultSet actual = QueryRunner.getResultSetFromSql("SELECT ...",
"tenant", "product");
assertEquals(rs, actual);
assertEquals("This is mocked value", actual.getString("foo"));
}
}
Also, some general advices:
Always use {} in each if-else statements even if they are one-lined. This will be much more convenient to merge and support your code in the future.
Override your code to manage database connections properly. They should be closed! Use some third-party connection pooling mechanism like Apache DBCP
Hope it helps!

Related

Java JDBC: Cannot insert Data into Database

I'm coding for hours to insert data into my SQL database, but nothing happens.
I even can't debug Java, because I don't get any output of my console.
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.sql.PreparedStatement;
import java.text.DecimalFormat;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
*
* #author xxx
*/
public class MyServlet extends HttpServlet {
private static final String URL = "jdbc:mysql://localhost:3306/userdata";
private static final String USER = "root";
private static final String PASSWORD = "root";
private static final DecimalFormat DF2 = new DecimalFormat("#.##");
private static Connection con;
private static Statement stmt;
private static ResultSet rs;
protected void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
try (PrintWriter out = response.getWriter()) {
try {
String myDriver = "com.mysql.jdbc.Driver";
try {
Class.forName(myDriver);
// opening database connection to MySQL server
con = DriverManager.getConnection(URL, USER, PASSWORD);
// getting Statement object to execute query
// the mysql insert statement
String query = "INSERT INTO customers (customer, currency, amount) values ('Name', 'Currency', 100);";
stmt.executeUpdate(query);
// execute the preparedstatement
// executing SELECT query
rs = stmt.executeQuery(query);
con.close();
stmt.close();
rs.close();
} catch (SQLException sqlEx) {
sqlEx.printStackTrace();
}
}
}
}
What did I wrong, that nothing happens? Even if I use this code for Java-Classes (not Servlets), I only receive an compile error, but without message.
I'm using the IDE Netbeans and mysql DB is the MySQL Workbench. The Java Class is using the main method.
Update:
I've tested following Code with IntelliJ:
import java.sql.*;
import java.util.logging.Level;
import java.util.logging.Logger;
public class Main {
public static void main(String[] args) {
String url = "jdbc:mysql://localhost:3306/userdata";
String user = "root";
String password = "root";
String query = "Insert into customers (customer, currency, amount) values('Michael Ballack', 'Euro', 500)";
try (Connection con = DriverManager.getConnection(url, user, password);
PreparedStatement pst = con.prepareStatement(query)) {
pst.executeUpdate();
} catch (SQLException ex) {
Logger lgr = Logger.getLogger(JdbcMySQLVersion.class.getName());
lgr.log(Level.SEVERE, ex.getMessage(), ex);
}
}
private static class JdbcMySQLVersion {
public JdbcMySQLVersion() {
}
}
I can insert data into the MySQL database.
In Netbeans this code won't work, although I've implemented the MySQLConnector. I don't know why, but Netbeans seems hard to handle.
In the servlet code, I don't see you ever write anything to out. So nothing is being sent back to the browser, even if it compiled. You could write your SQL exception to the out writer you created. To be more precise add this in your exception: out.println(sqlEx.printStackTrace()); That should at least show what exception you are getting back to the browser.
What is the compile error you get outside of a servlet?
This maybe obvious, but to get JDBC stuff to work on your server, you need to have the MySQL server installed, started and configured. The table referenced has to be defined, etc. You could check this outside of the Java servlet environment with the tools provided with MySQL.
your code can not compile, you miss catch exception for second 'try'.
Where do you use this class to run, if you run a java class, this class must contain main() function?
you should use some IDEs like eclipse or IntelliJ to code, it help you detect the error easier.
I found the solution. If you are using Netbeans with the Glassfish-Server and you want your servlet to save data into the database, you have to make sure that Netbeans has installed the Driver of your Database Connector (e.g. MySQL Connector). But you also have to configurate your server (e.g. Glassfish) which will support the DB Connector drivers.
In my case my Server didn't load the DB Connector Driver so the JDBC Code couldn't be executed.
Here's a useful link to configurate the Glassfish Server: https://dzone.com/articles/nb-class-glassfish-mysql-jdbc

NonWritableChannelException when trying to update an Access database

Using UCanAccess for the first time for a project and I am having a lot of trouble inserting a row into one of my database tables (in Microsoft Access).
My code makes sense but once I execute I end up getting the same error every time, even though NetBeans is able to connect to my database.
package Vegan;
import java.sql.Connection;
import java.sql.DriverManager;
public class connectionString {
static Connection connection = null;
public static Connection getConnection()
{
try
{
connection = DriverManager.getConnection("jdbc:ucanaccess://C://MyDatabase1.accdb");
System.out.println("---connection succesful---");
}
catch (Exception ex)
{
System.out.println("Connection Unsuccesful");
}
return connection;
}
package Vegan;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
public class DB {
private static ResultSet rs = null;
private static PreparedStatement ps = null;
private static Connection connection = null;
public DB() {
connection = connectionString.getConnection();
}
public void AddTest() {
try {
String sql = "INSERT INTO CategoryTbl(CategoryName) VALUES (?)";
ps = connection.prepareStatement(sql);
ps.setString(1, "Flours");
ps.executeUpdate();
System.out.println("Inserted");
} catch (Exception ex) {
System.out.println(ex.getLocalizedMessage().toString());
}
}
After that, when I execute the the AddTest() method, I get this system output:
run:
---connection succesful---
java.nio.channels.NonWritableChannelException
at sun.nio.ch.FileChannelImpl.write(FileChannelImpl.java:724)
at com.healthmarketscience.jackcess.impl.PageChannel.writePage(PageChannel.java:297)
UCAExc:::3.0.6 null
at com.healthmarketscience.jackcess.impl.PageChannel.writePage(PageChannel.java:234)
at com.healthmarketscience.jackcess.impl.TableImpl.writeDataPage(TableImpl.java:1375)
at com.healthmarketscience.jackcess.impl.TableImpl.addRows(TableImpl.java:1624)
at com.healthmarketscience.jackcess.impl.TableImpl.addRow(TableImpl.java:1462)
at net.ucanaccess.converters.UcanaccessTable.addRow(UcanaccessTable.java:44)
at net.ucanaccess.commands.InsertCommand.insertRow(InsertCommand.java:101)
at net.ucanaccess.commands.InsertCommand.persist(InsertCommand.java:148)
at net.ucanaccess.jdbc.UcanaccessConnection.flushIO(UcanaccessConnection.java:315)
at net.ucanaccess.jdbc.UcanaccessConnection.commit(UcanaccessConnection.java:205)
at net.ucanaccess.jdbc.AbstractExecute.executeBase(AbstractExecute.java:161)
at net.ucanaccess.jdbc.ExecuteUpdate.execute(ExecuteUpdate.java:50)
at net.ucanaccess.jdbc.UcanaccessPreparedStatement.executeUpdate(UcanaccessPreparedStatement.java:253)
at Vegan.DB.AddTest(DB.java:91)
at Vegan.TestDB.main(TestDB.java:17)
BUILD SUCCESSFUL (total time: 1 second)
With no changes being made to the database when I check on it again Access.
What could be causing this, and what does the error message mean? Thank you
"java.nio.channels.NonWritableChannelException" means that the database file cannot be updated. In your case that was because the database file was in the root folder of the Windows system drive (C:\) and mere mortals have restricted permissions on that folder.
Solution: Move the database file to a folder where you have full write access.

How to mock DriverManager.getConnection?

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

How to take input for a web service in java

I am trying to write a simple web service that must take a number as input and return details corresponding to it.
Here is my code that I have written till now.
package webserviceapp;
import java.sql.Statement;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;
import javax.jws.WebService;
import javax.jws.WebMethod;
#WebService
public class WebServiceApp {
/**
* #param args the command line arguments
*/
static final String JDBC_DRIVER = "com.mysql.jdbc.Driver";
static final String DB_URL = "jdbc:mysql://10.100.66.28:3306/dbname";
// Database credentials
static final String USER = "user";
static final String PASS = "pass";
static Map<Integer, String> map = new HashMap<Integer, String>();
public static void main(String[] args) {
// TODO code application logic here
Connection conn;
Statement stmt;
try{
Class.forName(JDBC_DRIVER);
conn = DriverManager.getConnection(DB_URL, USER, PASS);
stmt = (Statement) conn.createStatement();
String sql = "Select * from table";
ResultSet rs;
rs = stmt.executeQuery(sql);
while(rs.next()){
//do something
}
}catch(ClassNotFoundException | SQLException e){
System.out.println(e);
}
}
#WebMethod(action = "returnDetails")
public static String[] returnDetails(int k) throws notFoundException{
//do the work
//returns String[]
}
private static class notFoundException extends Exception {
public notFoundException(String s) {
System.out.println(s);
System.err.println(s);
}
}
}
I do not know how to take input for the above web service. I have a html page that has a text box and submit button for which I get values through a php code. I want to tunnel this number as input to my web service. Can anyone tell me how can I proceed.
Also, I want the output String[] to be returned to php code so it can be displayed on the html page.
Thanks in advance.
you can pass it in the URL and from the url you can get the values in java
Working off the assumption that you are looking to invoke a RESTful service, there are multiple ways of obtaining input parameters. You can refer to the below article for the ways to achieve this -
http://www.java4s.com/web-services/how-restful-web-services-extract-input-parameters
Code examples for each are available at http://www.java4s.com/web-services/
Another good article you can refer to is - https://vrsbrazil.wordpress.com/2013/08/07/passing-parameters-to-a-restful-web-service/

Testing Java code and previewing the SQL statement

The following is a Java (Hibernate) Method. How can I write a test for it? I want the test method to return a SQL statement.The code reference a lot of other classes and packages which already exist. Ignore these and just show me how to integrate them in my test program.
#Override
public AppTacticalSubUnit returnByCode(String code) throws MyOwnDAOException {
Session session = getSession();
UnitOfWork unitOfWork = new UnitOfWork();
try {
unitOfWork.beginTransaction(session);
Criteria criteria = session.createCriteria(AppTacticalSubUnit.class);
criteriaAppTacticalSubUnit.add(Restrictions.eq("code", code));
criteriaAppTacticalSubUnit.setResultTransformer(CriteriaSpecification.DISTINCT_ROOT_ENTITY);
setJoinFetches(criteria);
AppTacticalSubUnit ret = (AppTacticalUnit) criteria.uniqueResult();
unitOfWork.commit();
return ret;
} catch (HibernateException e) {
unitOfWork.rollback();
throw new ObelixxDAOException(e.getMessage(), e);
}
}
private void setJoinFetches(Criteria criteria) {
criteria.setFetchMode("appTacticalUnit.spaceOpsAreaServiceType", FetchMode.JOIN);
criteria.setFetchMode("appTacticalSubUnit.spaceOpsAreaServiceType.assExternalServiceType", FetchMode.JOIN);
criteria.setFetchMode("appTacticalSubUnit.spaceOpsAreaServiceType.assExternalServiceType.lookupServiceType", FetchMode.JOIN);
criteria.setFetchMode("appTacticalSubUnit.spaceOpsAreaServiceType.assExternalServiceType.lookupExternalServiceType", FetchMode.JOIN);
criteria.setResultTransformer(CriteriaSpecification.DISTINCT_ROOT_ENTITY);
criteria.addOrder(Order.asc("name"));
I have started something like this:
package na.co.sab.vitalix.db.dao;
import org.hibernate.Criteria;
import org.hibernate.FetchMode;
import org.hibernate.HibernateException;
import org.hibernate.criterion.CriteriaSpecification;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Restrictions;
import org.hsqldb.Session;
import na.co.sab.datashare.util.UnitOfWork;
import na.co.sab.vitalix.db.exception.MyOwnDAOException;
import na.co.sab.vitalix.db.util.HibernateOltpSessionUtil;
public class AppTacticalSubUnitTest {
//protected static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(AppOTacticalSubUnitTest.class);
static protected HibernateOltpSessionUtil dataShareInstance;
public static void initializeVitalixOnHsql() throws Exception {
initializeVitalixOnHsql(true);
Have a look at this article http://java.dzone.com/articles/how-get-jpqlsql-string seems like it describes what you want.
The idea is to use org.hibernate.Query#getQueryString() method.

Categories