...
FileLoader implementation code - refactored
Code Block | ||
---|---|---|
| ||
/* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ package com.celestial.mockito.filetodb; import java.io.IOException; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Paths; import java.util.*; /** * * @author selvy */ public class FileLoader { class IntWrapper { int value; } String fileToLoad; List<String> lines = Collections.emptyList(); public FileLoader(String fileToLoad) { this.fileToLoad = fileToLoad; } public List<String> getLines() { return lines; } int loadFile(String fname) { try { lines = Files.readAllLines(Paths.get(fname), StandardCharsets.UTF_8); } catch (IOException e) { } return calculateFileSize(); } int loadFile(ILoader func) { lines = func.loadFile(fileToLoad); return calculateFileSize(); } private int calculateFileSize() { IntWrapper result = new IntWrapper(); lines.forEach(line -> { result.value += line.length(); }); return result.value; } } |
DBConnector
LiveDBConnectorTest - not suitable for a build server and breaks the tenets of a good unit test
Code Block | ||
---|---|---|
| ||
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package com.celestial.mockito.filetodb;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import static org.junit.Assert.*;
import org.junit.Test;
import org.junit.BeforeClass;
import org.junit.Ignore;
import org.mockito.MockedStatic;
import org.mockito.Mockito;
/**
*
* @author selvy
*/
public class LiveDBConnectorTest
{
static String dbEndPoint = "jdbc:mysql://localhost:3306/";
static String dbName = "files";
// This test is not suitable for a build server. so we will need to stub
// IDbConnectionMgr
//@Ignore
@Test
public void open_connection() throws SQLException
{
// arrange
String dbEndPoint_ = "jdbc:mysql://localhost:3306/";
String dbName_ = "files";
IDbConnectionMgr connection = (endPoint, db) -> {
Connection conn = DriverManager.getConnection(endPoint+db, "root", "ppp");
return conn;
};
DBConnector cut = new DBConnector(connection);
// act
Connection conn = cut.openConnection(dbEndPoint_, dbName_);
// assert
assertNotNull(conn);
}
@Test
public void write_line_to_live_connection() throws SQLException
{
// arrange
IDbConnectionMgr connection = (endPoint, db) -> {
Connection conn = DriverManager.getConnection(endPoint+db, "root", "ppp");
return conn;
};
DBConnector cut = new DBConnector(connection);
cut.openConnection(dbEndPoint, dbName);
String lineToWrite = "be not changed by...";
int expectedLineNo = 1;
// act
// The idea of writeLine() is that each time a line is written to the DB
// it's line No should be returned. Line Nos start at 1
int lineNo = cut.writeLine(lineToWrite);
// assert
assertEquals(expectedLineNo, lineNo);
}
} |
DBConnector - Initial implementation
Code Block |
---|
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package com.celestial.mockito.filetodb;
import com.mysql.cj.xdevapi.PreparableStatement;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
*
* @author selvy
*/
public class DBConnector
{
private IDbConnectionMgr connectionMgr;
private Connection theConnection;
private int fileId;
private static final String SQL_INSERT_LINE = "insert into files.line_in_file" +
" values (default, ?, ?);";
private static final String SQL_LINE_COUNT = "select count(*) from files.line_in_file;";
DBConnector(IDbConnectionMgr connection)
{
connectionMgr = connection;
}
Connection openConnection(String dbEndPoint, String dbName) throws SQLException
{
theConnection = connectionMgr.openConnection(dbEndPoint, dbName);
return theConnection;
}
int writeLine(String lineToWrite)
{
int result = 0;
fileId = 1;
try
{
PreparedStatement ps = theConnection.prepareStatement(SQL_INSERT_LINE);
ps.setInt(1, fileId);
ps.setString(2, lineToWrite);
ps.executeUpdate();
ps = theConnection.prepareStatement(SQL_LINE_COUNT);
ResultSet rs = ps.executeQuery();
while (rs.next()){
result = rs.getInt(1);
}
} catch (SQLException ex)
{
Logger.getLogger(DBConnector.class.getName()).log(Level.SEVERE, null, ex);
}
return result;
}
} |
DBConnectorTest - suitable for a build pipeline and does not break the tenets of unit testing
Code Block |
---|
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package com.celestial.mockito.filetodb;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import static org.junit.Assert.*;
import org.junit.Test;
import org.junit.BeforeClass;
import org.junit.Ignore;
import org.mockito.MockedStatic;
import org.mockito.Mockito;
import static org.mockito.Mockito.spy;
/**
*
* @author selvy
*/
public class DBConnectorTest
{
static String dbEndPoint = "jdbc:mysql://localhost:3306/";
static String dbName = "files";
static Connection sqlConn = Mockito.mock(Connection.class);
// Mockito does not like the line below to be present in each test method
// it registers the static method with the current test thread once, if this line
// is called more than once in a unit test file, a Mockito exception is thrown
//
// The live DB connection code has been moved to it's own test file because
// it was pickup the mocked DriverManager and returning null because the
// params being passed in (real values) did not match the stubbed values
static MockedStatic<DriverManager> mockedDMgr = Mockito.mockStatic(DriverManager.class);
@BeforeClass
static public void beforeAllTestsDo()
{
// Because we are mocking the static, registration of the method should
// only occur once for the unit test file
mockedDMgr.when(() -> DriverManager.getConnection(dbEndPoint+dbName, "root", "ppp")).thenReturn(sqlConn);
}
@Test
public void open_connection_mocked() throws SQLException
{
// arrange
IDbConnectionMgr connection = (endPoint, db) -> {
Connection conn = DriverManager.getConnection(endPoint+db, "root", "ppp");
return conn;
};
DBConnector cut = new DBConnector(connection);
DBConnector spyCut = spy(cut);
int expectedLineNoCount = 1;
Mockito.doReturn(1).when(spyCut).queryLinesInDB();
// act
Connection conn = spyCut.openConnection(dbEndPoint, dbName);
int lineNoResult = spyCut.getLineCount();
// assert
assertNotNull(conn);
assertEquals(expectedLineNoCount, lineNoResult);
}
@Test
public void write_line_to_mocked_connection() throws SQLException
{
// arrange
IDbConnectionMgr connection = (endPoint, db) -> {
Connection conn = DriverManager.getConnection(endPoint+db, "root", "ppp");
return conn;
};
DBConnector cut = new DBConnector(connection);
DBConnector spyCut = spy(cut);
Mockito.doReturn(0).when(spyCut).queryLinesInDB();
PreparedStatement ps = Mockito.mock( PreparedStatement.class );
Mockito.when(sqlConn.prepareStatement(Mockito.any())).thenReturn(ps);
spyCut.openConnection(dbEndPoint, dbName);
String lineToWrite = "be not changed by...";
int expectedLineNo = 1;
// act
// The idea of writeLine() is that achg time a line is written to the DB
// it's line No should be returned. Line Nos start at 1
int lineNo = spyCut.writeLine(lineToWrite);
// assert
assertEquals(expectedLineNo, lineNo);
}
} |
DBConnector - refactored
Code Block |
---|
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package com.celestial.mockito.filetodb;
import com.mysql.cj.xdevapi.PreparableStatement;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
*
* @author selvy
*/
public class DBConnector
{
private final IDbConnectionMgr connectionMgr;
private Connection theConnection;
private int fileId = 1;
private int itsLineCount;
private static final String SQL_INSERT_LINE = "insert into files.line_in_file" +
" values (default, ?, ?);";
private static final String SQL_LINE_COUNT = "select count(*) from files.line_in_file;";
DBConnector(IDbConnectionMgr connection)
{
connectionMgr = connection;
}
Connection openConnection(String dbEndPoint, String dbName) throws SQLException
{
theConnection = connectionMgr.openConnection(dbEndPoint, dbName);
itsLineCount = queryLinesInDB();
return theConnection;
}
public int getLineCount()
{
return itsLineCount;
}
public void updateLineCount()
{
updateLineCount(getLineCount() + 1);
}
public void updateLineCount(int value)
{
itsLineCount = value;
}
public int getFileId()
{
return fileId;
}
int queryLinesInDB()
{
try
{
PreparedStatement ps = theConnection.prepareStatement(SQL_LINE_COUNT);
ResultSet rs = ps.executeQuery();
while (rs.next()){
itsLineCount = rs.getInt(1);
}
} catch (SQLException ex)
{
Logger.getLogger(DBConnector.class.getName()).log(Level.SEVERE, null, ex);
}
return itsLineCount;
}
public int writeLine(String lineToWrite)
{
int fileId = getFileId();
try
{
PreparedStatement ps = theConnection.prepareStatement(SQL_INSERT_LINE);
ps.setInt(1, fileId);
ps.setString(2, lineToWrite);
ps.executeUpdate();
updateLineCount();
} catch (SQLException ex)
{
Logger.getLogger(DBConnector.class.getName()).log(Level.SEVERE, null, ex);
}
return getLineCount();
}
} |
Interfaces
Code Block |
---|
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package com.celestial.mockito.filetodb;
import java.util.List;
/**
*
* @author selvy
*/
@FunctionalInterface
public interface ILoader
{
List<String> loadFile(String fname);
}
|