How to mock DriverManager.getConnection? - java

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.

Related

Mocking Result Set using mockito

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!

NoClassDefFoundException while trying to use HikariCP [duplicate]

This question already has answers here:
Why am I getting a NoClassDefFoundError in Java?
(31 answers)
Closed 6 years ago.
I'm so noob at external stuff to Bukkit programming, so I'm sorry if it's so easy to solve :P
I have a problem, and it's that when I try to use HikariCP in my project, it returns in an error (the title one).
I'm using it in a BungeeCord plugin.
The weird thing is that I have done this successfully couples of times, and I don't know why it isn't working this time.
The error / log:
06:13:36 [ADVERTENCIA] Exception encountered when loading plugin: DiverseReport java.lang.NoClassDefFoundError: com/zaxxer/hikari/HikariDataSource at net.srlegsini.DiverseReport.Bungee.MClass.onEnable(MClass.java:44) at net.md_5.bungee.api.plugin.PluginManager.enablePlugins(PluginManager.java:227) at net.md_5.bungee.BungeeCord.start(BungeeCord.java:272) at net.md_5.bungee.BungeeCordLauncher.main(BungeeCordLauncher.java:55) at net.md_5.bungee.Bootstrap.main(Bootstrap.java:15) Caused by: java.lang.ClassNotFoundException: com.zaxxer.hikari.HikariDataSource at net.md_5.bungee.api.plugin.PluginClassloader.loadClass0(PluginClassloader.java:53) at net.md_5.bungee.api.plugin.PluginClassloader.loadClass(PluginClassloader.java:27) at java.lang.ClassLoader.loadClass(Unknown Source) ... 5 more
My main class:
package net.srlegsini.DiverseReport.Bungee;
import java.io.File;
import java.io.IOException;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Arrays;
import com.zaxxer.hikari.HikariDataSource;
import net.md_5.bungee.BungeeCord;
import net.md_5.bungee.api.plugin.Plugin;
import net.md_5.bungee.config.Configuration;
import net.md_5.bungee.config.ConfigurationProvider;
import net.md_5.bungee.config.YamlConfiguration;
import net.srlegsini.DiverseReport.Bukkit.UUIDFetcher;
public class MClass extends Plugin {
static Configuration config;
static MClass plugin;
static HikariDataSource hikari;
static Connection connection;
public void onEnable() {
BungeeCord.getInstance().getPluginManager().registerListener(this, new ChannelListener());
BungeeCord.getInstance().registerChannel("Return");
loadCfg();
if (!config.contains("MySQL")) {
config.set("MySQL.Enable", false);
config.set("MySQL.Host", "localhost");
config.set("MySQL.Port", 3306);
config.set("MySQL.User", "user");
config.set("MySQL.Pass", "pass");
config.set("MySQL.Database", "Sr_DiverseReport");
}
saveCfg(getDataFolder());
hikari = new HikariDataSource();
hikari.setDataSourceClassName("com.mysql.jdbc.jdbc2.optional.MysqlDataSource");
hikari.addDataSourceProperty("serverName", config.getString("MySQL.Host"));
hikari.addDataSourceProperty("port", 3306);
hikari.addDataSourceProperty("databaseName", config.getString("MySQL.Database"));
hikari.addDataSourceProperty("user", config.getString("MySQL.User"));
hikari.addDataSourceProperty("password", config.getString("MySQL.Pass"));
try {
Class.forName("com.mysql.jdbc.Driver");
connection = hikari.getConnection();
} catch (SQLException e1) {
e1.printStackTrace();
} catch (ClassNotFoundException e2) {
}
saveCfg(getDataFolder());
}
public void loadCfg() {
try {
File file = new File(getDataFolder(), "config.yml");
if (!getDataFolder().exists()) {
getDataFolder().mkdir();
}
if (!file.exists()) {
file.createNewFile();
}
config = ConfigurationProvider.getProvider(YamlConfiguration.class)
.load(new File(getDataFolder(), "config.yml"));
} catch (IOException e) {
e.printStackTrace();
}
}
public static void saveCfg(File dataFolder) {
try {
ConfigurationProvider.getProvider(YamlConfiguration.class).save(config, new File(dataFolder, "config.yml"));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
#SuppressWarnings({ "unused", "deprecation" })
public static String getUUID(String playerName) {
UUIDFetcher fetcher = new UUIDFetcher(Arrays.asList("evilmidget38", "mbaxter"));
String playerUUID = null;
try {
playerUUID = UUIDFetcher.getUUIDOf(playerName).toString();
} catch (Exception e2) {
playerUUID = BungeeCord.getInstance().getPlayer(playerName).getUniqueId().toString();
}
return playerUUID;
}
}
My procedure:
Create the project, import BungeeCord.jar, HikariCP-2.6.0.jar and slf4j-api-1.7.21.jar in buildpath, import HikariCP-2.6.0.jar and slf4j-api-1.7.21.jar
It worked in other projects, but magically, it's broken.
I don't want to use Maven, just because it must have a fix, because as I said, I used this same procedure so many times in the past.
Thank you for taking the time to read this :)
EDIT:
Image of the project
It's all in the exception:
Caused by: java.lang.ClassNotFoundException: com.zaxxer.hikari.HikariDataSource
The HikariDataSource is missing at runtime, you need to provide it somehow, for example by copying the relevant .jar with 'drivers' into your server libraries folder.
Also see some related questions:
How to set up datasource with Spring for HikariCP? and
How do I configure HikariCP in my Spring Boot app in my application.properties files?
From the exception it is clear that HikariCP-2.6.0.jar was in classpath during compile time but is missing in runtime and from the image of the project structure, it is also clear that both HikariCP-2.6.0.jar and slf4j-api-1.7.21.jar are missing as library reference in the ide. You need to keep these jar in your classpath library during compile time and runtime.

make a connection from my program to database

I am new to programming and i am trying to make a connection from my program to database but when i make the code,error occurred on line 34 (package con.msql.jdbc does not exit).Can u tell me why??help me
code :
package Absensi_PEgawai;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import javax.swing.JOptionPane;
public class koneksi {
private static Connection koneksi;
public static Connection getKoneksi()
{
//cek koneksi
if(koneksi == null)
{
try
{
String url;
url = "jdbc:mysql://localhost:3306/dbabsensipegawai";
String user = "root";
String password = "pk12basketboy";
line34 --> **DriverManager.registerDriver(new con.mysql.jdbc.Driver());**
koneksi = DriverManager.getConnection(url,user,password);
}catch(SQLException t)
{
JOptionPane.showMessageDialog(null, "Error Membuat Koneksi");
}
}
return koneksi;
}
static Object getConnection()
{
throw new UnsupportedOperationException("Not Yet Implemented");
}
}
You must have forgotten to add the database driver to the CLASSPATH. If you are under Eclipse, go to the Build path menu and add your driver, otherwise refer to the billion posts on the internet that explain how to add a class to the CLASSPATH for any system.

Please help me with JUnit test cases for the code below

I want to know the JUnit test cases for the following program.please help. I have not included the main method here. Want to know the JUnit test cases for the url() method in the code. This code is to read HTML from a website and save it in a file in local machine
package Java3;
import java.io.BufferedReader;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.logging.Level;
import java.util.logging.Logger;
public class Urltohtml
{
private String str;
public void url() throws IOException
{
try
{
FileOutputStream f=new FileOutputStream("D:/File1.txt");
PrintStream p=new PrintStream(f);
URL u=new URL("http://www.google.com");
BufferedReader br=new BufferedReader(new InputStreamReader(u.openStream()));
//str=br.readLine();
while((str=br.readLine())!=null)
{
System.out.println(str+"\n");
p.println(str);
}
}
catch (MalformedURLException ex)
{
Logger.getLogger(Urltohtml.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
I would rename that class to UrlToHtml and write a single JUnit test class UrlToHtmlTest.
Part of the reason why you're having problems testing this is that the class is poorly designed and implemented:
You should pass in the URL you want to scrape, not hard code it.
You should return the content as a String or List, not print it to a file.
You might want to throw that exception rather than catch it. Your logging isn't exactly "handling" the exceptional situation. Let it bubble out and have clients log if they wish.
You don't need that private data member; return the contents. That lets you make this method static.
Good names matter. I don't like what you have for the class or the method.
Why are you writing this when you could use a library to do it?
Here's what the test class might look like:
public class UrlToHtmlTest {
#Test
public void testUrlToHtml() {
try {
String testUrl = "http://www.google.com" ;
String expected = "";
String actual = UrlToHtml.url(testUrl);
Assert.assertEquals(expected, actual);
} catch (Exception e) {
e.printStackTrace();
Assert.fail();
}
}
}

How to use Java Property File?

I need to use .properties file in Java to store database information.
Here is my database connector class. It's giving NullPointerException. What is the issue with my code ?
Note, that I haven't' assign those property file values. DB connection values are still hard coded.
import java.io.IOException;
import java.io.InputStream;
import java.sql.Statement;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Properties;
import java.util.logging.Level;
import java.util.logging.Logger;
public final class Database {
public Connection connection;
private Statement statement;
private Properties property;
public static Database database;
private Database() {
String url = "jdbc:mysql://localhost:3306/";
String dbName = "edus";
String driver = "com.mysql.jdbc.Driver";
String userName = "root";
String password = "";
try {
InputStream is = Database.class.getClassLoader().getResourceAsStream(
"config.properties");
property.load(is);
System.out.println(property.getProperty("db_user"));
System.out.println(property.getProperty("db_password"));
System.out.println(property.getProperty("db_name"));
Class.forName(driver).newInstance();
this.connection = (Connection) DriverManager.getConnection(url + dbName,
userName, password);
}catch (IOException ex) {
Logger.getLogger(Database.class.getName()).log(Level.SEVERE, null, ex);
} catch (ClassNotFoundException e) {
System.out.println("JDBC driver is missing");
} catch (InstantiationException | IllegalAccessException | SQLException e) {
e.printStackTrace();
}
}
public static synchronized Database getDatabaseConnection() {
if (database == null) {
database = new Database();
}
return database;
}
}
config.properties is not lying under classpath. It should be under classes folder.
you can also try
Database.class.getClassLoader().getResourceAsStream(
"com/lk/apiit/eduservice/config.properties");
As Roman C pointed out you also need to initialize Properties Object first
Properties property = new Properties();
You forgot to initialize
Properties property = new Properties();
This is an issue of NullPointerException in your code, because you referenced not initialized variable.
If you open a stream you should close it after it's not used. Do it by adding finally block.
The code where you getting a connection to the database you can move to the corresponding method. If the connection is closed you will not reinitialize the database again just reopen a connection or get a new one.
Dont keep config properties file in a package. Keep it directly inside the source folder, so that the config properties file comes directly in the build/classes folder after the build is done.
The issue is that your config properties in in the folder com/ik/apiit/eduservice folder but your code is expecting it to be directly in the classes folder (the root folder of classpath).
try this
FileInputStream in = new FileInputStream(System.getProperty("WEB-INF/dbConnection.properties"));
prop.load(in);

Categories