How to test JDBI DAO's with H2-in-memory database? - java

I'm using Dropwizard framework with JDBI and h2-in-memory for my test purposes. Also I've written my DAOs, and now I want to test them with unit tests. I came along the DBUnit which seem to fit my requirements.
But how to integrate it with JDBI and fill it with test data?

I implemented it like this:
I created a base dao class that sets up my DW environment to build a DBI instance for me. This looks like that:
#BeforeClass
public static void setup() {
env = new Environment( "test-env", Jackson.newObjectMapper(), null, new MetricRegistry(), null );
dbi = new DBIFactory().build( env, getDataSourceFactory(), "test" );
dbi.registerArgumentFactory(new JodaDateTimeArgumentFactory());
dbi.registerMapper(new JodaDateTimeMapper(Optional.absent()));
}
static DataSourceFactory getDataSourceFactory()
{
DataSourceFactory dataSourceFactory = new DataSourceFactory();
dataSourceFactory.setDriverClass( "org.h2.Driver" );
dataSourceFactory.setUrl( "jdbc:h2:mem:testDb" );
dataSourceFactory.setUser( "sa" );
dataSourceFactory.setPassword( "" );
return dataSourceFactory;
}
public static DBI getDbi() {
return dbi;
}
public static Environment getEnvironment() {
return env;
}
Not this will create a Datasource for you pointing to your in-memory database.
No in the actual test you can use the DBI instance to create your DAOs before the test:
DaoA dao;
DaoB otherDao;
#Before
public void setupTests() throws IOException {
super.setupTests();
dao = dbi.onDemand(DaoA.class);
otherDao = dbi.onDemand(DaoB.class);
}
With this your good to go and you can start testing. Hope that helps.
Artur
Edit for init:
My tests initialise themselves as well. For that I use dbi directly to execute sql scripts. For example, a test is associated with a test1.sql script that is a test classpath resource. In that case, all I need to do is read that script and run it before the test. For example like this:
StringWriter writer = new StringWriter();
InputStream resourceStream = this.getClass().getResourceAsStream("/sql/schema.sql");
if(resourceStream == null ) {
throw new FileNotFoundException("schema not found");
}
IOUtils.copy(resourceStream, writer);
Handle handle = null;
try {
handle = dbi.open();
handle.execute(writer.toString());
handle.commit();
} finally {
handle.close();
if(resourceStream != null) {
resourceStream.close();
}
writer.close();
}

Related

Mockito - How to avoid inserting data into DB?

How can we write mockito for the below code? It's been written in normal JDBC. I need to create a mock of all this code having main method (which is driving all the logic of updating the data).
I am really need help in mocking the avoid inserting the actual data. Could someone please guide me ?
public class PaytPaytmBilling {
private static Category logger = Category.getInstance(PaytPaytmBilling.class);
private static InputStream inputS = XY.class.getResourceAsStream("/paytm.properties");
private static final INSERT_QUERY = "INSERT STATEMENT";
private static void insertPaytPaytmBilling(ArrayList allPaytPaytmBill) throws Exception{
conn = getConnection(userId, passwd, prop.getProperty("databaseURL"));
String childSql = buildInsertPaytPaytmBillSql();
PreparedStatement pStatement = conn.prepareStatement(childSql);
for (int i=0; i<allPaytPaytmBill.size(); i++){
PaytPaytmBill PaytmBill = (PaytPaytmBill) allPaytPaytmBill.get(i);
pStatement.setString(1, PaytmBill.getXX());
pStatement.setString(2, PaytmBill.getYY());
pStatement.setString(3, PaytmBill.getAA());
pStatement.setLong(4, PaytmBill.getBB());
pStatement.setLong(5, PaytmBill.getCC));
pStatement.setString(6, PaytmBill.getDD());
pStatement.setInt(7, PaytmBill.getEE());
pStatement.setInt(8, PaytmBill.getFF());
pStatement.setString(9, "");
pStatement.setString(10, "");
pStatement.execute();
}
pStatement.close();
conn.close();
}
private static void getDbConn() throws Exception {
// Here get DB connection
}
public static void main(String[] args) throws Exception
{
ArrayList allPaytPaytmBill = new ArrayList();
XY.init();
getDbConn();
// This query reads data from other tables and creates the data..
String qmrString = qmr.buildQmrSql();
allPaytPaytmBill = qmr.getAllMemberData(qmrString);
insertPaytPaytmBilling(allPaytPaytmBill);
}
}
Mockito Test class:
#RunWith(MockitoJUnitRunner.class)
public class PaytmBillingTest {
private static Category logger = Category.getInstance(PaytmBillingTest.class);
#Mock
private DataSource ds;
#Mock
private Connection c;
#Mock
private PreparedStatement stmt;
#Mock
private ResultSet rs;
private ArrayList<PaytmBill> allPaytmBill;
#Before
public void before() {
allPaytmBill = new ArrayList<>();
PaytmBill PaytmBill = new PaytmBill();
PaytmBill.setAA("1182");
PaytmBill.setBB("5122");
PaytmBill.setCC("201807");
PaytmBill.setDD(0L);
PaytmBill.setEE(100);
PaytmBill.setFF(0);
PaytmBill.setGG(0);
PaytmBill.setHH("A");
PaytmBill.setII(null);
PaytmBill.setJJ(null);
allPaytmBill.add(PaytmBill);
}
#Test
public void testPaytmBilling() {
PaytmBilling PaytmBilling = new PaytmBilling();
}
}
First of all, it looks like you are not showing use the real code. For example you added private static void getDbConn() but the code calls conn = getConnection(...), the variable conn is not declared anywhere, etc. This makes it harder to really help with your issue.
Looking at your unit test, you want to mock instances of certain classes used by PaytPaytmBilling, like DataSource, Connection and PreparedStatement. These are called 'dependencies'.
In order to do that, you need to change PaytPaytmBilling so that these dependencies are 'injected' (see Dependency Injection). This means they are provided to PaytPaytmBilling via the constructor or a setter (or with some frameworks just by adding an annotation on the field).
In the current code, the dependencies are obtained by PaytPaytmBilling itself (e.g. by calling a static method, or creating a new instance) and they cannot be mocked (except via some black magic mocking frameworks which I don't advise you to get into right now).
To write good unit tests, you need to write (or refactor) the code to be testable, which means dependencies are injected, not obtained internally in the class. Also avoid static methods and data (constants are ok), they don't play nice with dependency injection and testable code.
So for example the DataSource could be injected via the constructor like this:
public class PaytPaytmBilling {
private static final String CHILD_SQL = "SELECT bladiebla...";
private DataSource dataSource;
public PaytPaytmBilling(DataSource dataSource) {
this.dataSource = dataSource;
}
public void insertPaytPaytmBilling(List<PaytmBill> allPaytPaytmBill) {
// keeping the example simple here.
// don't use String literals for the parameters below but read
// them from Properties (which you can mock for the unit test)
Connection conn = dataSource.getConnection("userId", "passwd", "url");
PreparedStatement pStatement = conn.prepareStatement(CHILD_SQL);
for (int i=0; i<allPaytPaytmBill.size(); i++){
PaytPaytmBill PaytmBill = (PaytPaytmBill) allPaytPaytmBill.get(i);
pStatement.setString(1, PaytmBill.getXX());
pStatement.setString(2, PaytmBill.getYY());
pStatement.setString(3, PaytmBill.getAA());
// ...
pStatement.execute();
}
pStatement.close();
conn.close();
}
If you re-write the code like above, you could test it like this:
#RunWith(MockitoJUnitRunner.class)
public class PaytmBillingTest {
// this will cause Mockito to automatically create an instance
// and inject any mocks needed
#InjectMocks
private PaytmBilling instanceUnderTest;
#Mock
private DataSource dataSource;
// connection is not directly injected. It is obtained by calling
// the injected dataSource
#Mock
private Connection connection;
// preparedStatement is not directly injected. It is obtained by
// calling the connection, which was obtained by calling the
// injected dataSource
#Mock
private PreparedStatement preparedStatement;
private List<PaytmBill> allPaytmBill;
#Before
public void before() {
allPaytmBill = new ArrayList<>();
PaytmBill paytmBill = new PaytmBill();
paytmBill.setAA("1182");
paytmBill.setBB("5122");
paytmBill.setCC("201807");
paytmBill.setDD(0L);
paytmBill.setEE(100);
paytmBill.setFF(0);
paytmBill.setGG(0);
paytmBill.setHH("A");
paytmBill.setII(null);
paytmBill.setJJ(null);
allPaytmBill.add(PaytmBill);
}
#Test
public void testPaytmBilling() {
// given
when(dataSource.getConnection(anyString(), anyString(), anyString())).thenReturn(connection);
when(connection.prepareStatement(anyString())).thenReturn(preparedStatement);
// when
instanceUnderTest.insertPaytPaytmBilling(allPaytPaytmBill);
// then
verify(pStatement).setString(1, paytmBill.getXX());
verify(pStatement).setString(2, paytmBill.getYY());
verify(pStatement).setString(3, paytmBill.getAA());
// ...
verify(pStatement).execute();
verify(pStatement).close();
verify(connection).close();
}
Unrelated suggestion regarding your code: It's better to close resources in a finally block, or using try-with resources. In you current code resources will not be closed if an exception occurs whilst processing on the resources:
Connection conn = dataSource.getConnection("userId", "passwd", "url");
PreparedStatement pStatement = conn.prepareStatement(childSql);
try {
// processing steps
}
finally {
pStatement.close();
conn.close();
}
Or try-with-resources:
try (Connection conn = dataSource.getConnection("userId", "passwd", "url"),
PreparedStatement pStatement = conn.prepareStatement(childSql)) {
// processing steps
}
Since Connection and PreparedStatement implement the AutoCloseable interface they will be closed automatically when the try block ends. This is possible since Java 7.

How to use Mockito to mock including an EntityManager

Currently in school we are working on a rather large project. However testing in Java wasn't really explained that well so I didn't really work TDD like I was suppose to.
protected EntityManager getEntityManager() {
return EntityController.getEntityManager();
}
// Get all exam skeletons from the DB
#Override
public List<ExamSkeleton> getAllSkeletons() {
EntityManager entityManager = getEntityManager();
try {
TypedQuery<ExamSkeleton> query = entityManager.createQuery("SELECT NEW ExamSkeleton (s.id, s.filename, s.course, s.visible) FROM ExamSkeleton as s", ExamSkeleton.class);
List<ExamSkeleton> skeletons = query.getResultList();
return skeletons;
} catch (IllegalArgumentException exception) {
LOGGER.error(exception);
}
return Collections.emptyList();
}
So my question is, how do I test this method using Mockito?
Approach 1: Test the Code As Is
The getEntityManager method is private and it invokes a static method so, as things stand, you would need to use PowerMockito to provide a mocked instance of EntityManager in your test. For example:
#RunWith(PowerMockRunner.class)
#PrepareForTest({EntityController.class})
public class SomeTest {
#Test
public void aTest() {
PowerMockito.mockStatic(EntityController.class);
EntityManager entityManager = Mockito.mock(EntityManager.class);
Mockito.when(EntityController.getEntityManager()).thenReturn(entityManager);
TypedQuery<ExamSkeleton> query = (TypedQuery<ExamSkeleton>) Mockito.mock(TypedQuery.class);
Mockito.when(entityManager.createQuery("SELECT NEW ExamSkeleton (s.id, s.filename, s.course, s.visible) FROM ExamSkeleton as s")).thenReturn(query);
List<ExamSkeleton> expected = new ArrayList<>();
Mockito.when(query.getResultList()).thenReturn(expected);
ExamRepository examRepository = new ExamRepository();
List<ExamSkeletons> actual = examRepository.getAllSkeletons();
// this assertion verifies that getAllSkeletons gives you the result of the above SQl query
assertSame(expected, actual);
}
}
Approach 2: Refactor For Separation of Concerns and Ease of Testing
However, you could simplify things, from a testing and design perspective, by externalising the creation of the entity manager into a factory, for example.
public class EntityManagerFactory {
public EntityManager create() {
return EntityController.getEntityManager();
}
}
Next, inject an instance of EntityManagerFactory into whatever class contains getAllSkeletons() (i.e. the class you are testing). The simplest way of doing this is to declare it as a constructor argument:
public class SomeDao {
private final EntityManagerFactory entityManagerFactory;
public SomeDao(EntityManagerFactory entityManagerFactory) {
this.entityManagerFactory = entityManagerFactory;
}
#Override
public List<ExamSkeleton> getAllSkeletons() {
try {
TypedQuery<ExamSkeleton> query = entityManager.createQuery("SELECT NEW ExamSkeleton (s.id, s.filename, s.course, s.visible) FROM ExamSkeleton as s", ExamSkeleton.class);
List<ExamSkeleton> skeletons = query.getResultList();
return skeletons;
} catch (IllegalArgumentException exception) {
LOGGER.error(exception);
}
return Collections.emptyList();
}
}
Now, you can test this code using vanilla mockito. For example:
public class SomeDaoTest {
#Test
public void canGetAllSkeletons() {
EntityManagerFactory entityManagerFactory = Mockito.mock(EntityManagerFactory.class);
Mockito.when(entityManagerFactory.create()).thenReturn(entityManager);
SomeDao sut = new SomeDao(entityManagerFactory.class);
// now SomeDao will use your mocked EntityManager so you can set expectations
// on createQuery etc to drive your test scenarios
// ...
}
}
1) The EntityManager should not be associated to the controller :
return EntityController.getEntityManager();
In terms of design, it is not desirable : low layer and high layer should not be mixed, otherwise why use them ?
In terms of testing for getAllSkeletons(), this coupling will also make the unit test harder to set and to write.
2) The actual method doesn't have logic to test but the exception case : you just create a query, execute it and return the result.
It is a good case for an integration test (without mocking the DB layer), less for an unit test.
As it will make the unit test complex and with not a lot of value.
Example of what you could get with Mockito and that I don't recommend.
Make the EntityManager a dependency of the class under test : with injection or not.
In your unit test, mock this dependency.
It could look like :
#Mock
EntityManager entityManagerMock;
#Test
public void getAllSkeletons(){
TypedQuery<ExamSkeleton> queryByMock = (TypedQuery<ExamSkeleton>) Mockito.mock(TypedQuery.class);
Mockito.when(entityManagerMock.createQuery("SELECT NEW ExamSkeleton (s.id, s.filename, s.course, s.visible) FROM ExamSkeleton as s"))
.thenReturn(queryByMock);
List<ExamSkeleton> skeletons = new ArrayList<>();
Mockito.when(queryByMock.getResultList())
.thenReturn(skeletons);
Foo foo = new Foo();
foo.setEntityManager(entityManagerMock);
// action
List<ExamSkeleton> actualSkeletons = foo.getAllSkeletons();
// assertion
Assert.assertSame(skeletons, actualSkeletons);
}
Really don't write this kind of code that just describes the flow of invocations.
It makes just a test brittle that will very rarely catch regressions.

How to load the HSQL DB once before running all junit in Java project

My project is not Spring based .Its a java with Hibernate.Building tool - Maven.
I am loading data from one database to HSQL DB before running junits.
My DB util class:
public class DatabaseUtil {
SchemaLoad schemaLoad = new SchemaLoad();
DataLoad dataLoad = new DataLoad();
boolean dataLoaded = false;
static final String filename1 = "test1.txt";
static final String filename2 = "text2.txt";
void dbLoad() throws SQLException {
if (!dataLoaded) {
schemaLoad.cloneSchema(filename1);
dataLoad.exportData(filename2);
System.out.println("***********executed**********8");
dataLoaded = true;
}
}
}
First Test Case:
public class TestCase {
TrainRepository trainRepository = new TrainRepositoryImpl();
DatabaseUtil databaseUtil = new DatabaseUtil();
#BeforeClass
private void setUp() throws SQLException {
databaseUtil.dbLoad();
}
#Test
private void positiveTestCaseForTrainRepo() throws Exception {
//TestCases
}
Second Test case:
public class TestCase1 {
AirRepository airRepository = new AirRepositoryImpl();
DatabaseUtil databaseUtil = new DatabaseUtil();
#BeforeClass
private void setUp() throws SQLException {
databaseUtil.dbLoad();
}
#Test
private void positiveTestCaseForAirRepo() throws Exception {
//TestCases
}
Both the test cases are running fine.But Its executing databaseUtil.dbLoad(); method on each junit.
My question is I need to load the database only once ie before start of first junit and need to set some indicator .The further junits need to check the DB instance If DB instance is there it should not load the data ie DatabaseUtil class need to be singleton.
All the junits are running through maven suffire plugin during mvn install phase.
Kindly help me to achieve this.
void dbLoad() will be called each time.
then use a static variable to keep track
static boolean dataLoaded = false;
if you don't use spring you need to implement caching yourself. you have a few option. use static field with some kind of synchronization (in case you use/plan to use threads). other option is to switch to testng that gives you #BeforeGroup functionality so you can mark all your db tests and have your initialization run before.

grails spock testing failing with 'java.lang.IllegalArgumentException: ServletContext must not be null'

I having a method in command class, which use messageSource.getMessage(...), as messageSource won't get injected into the commandClass. I use
def messageSource = Holders.applicationContext.getBean("messageSource") inside the commandClass.
My problem is when trying to write unit test this method,
#Before
void setup() {
Holders.applicationContext.getBean("messageSource")
}
void "testFunction"() {
//inside testFunction I am using messageSource
given:
//required things
when:
//call the function
then:
//assert
}
after testing this function, I getting the error
java.lang.IllegalArgumentException: ServletContext must not be null
at grails.util.Holders.getApplicationContext(Holders.java:80)
Can someone suggest on how to resolve this one.
Update
#Validateable
class commandClass {
//required fields and constraints
def formatData(List<commandClass> commandObjs) {
StringBuilder validationErrors
commandObjs.each {commandObj->
validationErrors = new StringBuilder()
if(commandObj.hasErrors()) {
commandObj.errors.allErrors.each {it ->
validationErrors.append(messageSource.getMessage(it, null)).append('\n')
}
}
commandObj.metaClass.validationErrors = validationErrors
}
}
}
Thanks in Advance
I found the answer
void setup() {
mockApplicationContext()
}
def static mockApplicationContext() {
GrailsUnitTestMixin.initGrailsApplication()
Holders.grailsApplication = GrailsUnitTestMixin.grailsApplication
Holders.metaClass.'static'.getApplicationContext = { ->
return GrailsUnitTestMixin.applicationContext
}
Holders.metaClass.applicationContext.getBean = { bean ->
return GrailsUnitTestMixin.messageSource
}
}
I 'll update more about the answer later
============UPDATED ANSWER========================
Right now I am using grails 2.4.2.
Here you do not need to use Holders.applicationContext.getBean("messageSource") to get messageSource, it will be automatically injected.
So the example of the Command object:
#Validateable
class Test {
def messageSource
String aa
static constraints = {
aa blank:false, validator: {val, obj ->
println obj.messageSource.getMessage("default.paginate.prev",null,LocaleContextHolder.locale)
...
}
...
The example of the test :
void "test for valid data"() {
when:
def test = new Test(aa:'hello')
def messageSource = Mock(MessageSource)
test.messageSource = messageSource
then:
test.validate()
}
Instead of Mock, you can also use mockFor.
=========OLD ANSWER============
Instead of directly using messageSource in Command object, you can use service there and wrap the messageSource by the service.
The example of the service :
class I18nMessageService {
MessageSource messageSource
def getMessage(String code, Object[] args=null) {
messageSource.getMessage(code,args,LocaleContextHolder.locale)
}
}
The example of the Command object :
#Validateable
class Test {
def i18nMessageService
String aa
static constraints = {
aa blank:false, validator: {val, obj ->
println obj.i18nMessageService.getMessage("default.paginate.next")
...
}
}
}
The i18nMessageService is automatically injected to the Test command object while running app.
For test, i18nMessageService should be mocked and injected manually.
The example of the test :
void "test for valid data"() {
when:
def test = new Test(aa:'hello')
def i18nMessageServiceMock = mockFor(I18nMessageService)
i18nMessageServiceMock.demand.getMessage {'message you wanted'}
test.i18nMessageService = i18nMessageServiceMock.createMock()
then:
test.validate()
}
If you are using Grails 3, you just to add the annotation
#TestMixin(GrailsUnitTestMixin)
before your class definition.
This will inject a variable called applicationContext in your unit test.

Making a "TransactionAction" inner class

I've got a Spring + Hibernate + MySQL web application, which is just a hello-world-test-area for now.
One of my Service classes implements this method:
public List<Offerta> tutte() {
List<Offerta> tutte = null;
TransactionStatus status = txm.getTransaction( new DefaultTransactionDefinition() );
try {
tutte = dao.getAll(Offerta.class);
txm.commit(status);
} catch (Exception e) {
e.printStackTrace();
txm.rollback(status);
}
return tutte;
}
'txm' is an injected PlatformTransactionManager.
What I want now, is to avoid duplicating the "wrapping" transaction code in all my service's methods!
I would like something like this:
someHelperTransactionClass.doThisInTransaction(new TransactionAction() {
List l = dao.queryForSomething();
});
But that's a inner class: how can I pass in and out data from it? I mean, how can I get the resulting "l" list from that TransactionAction? You could answer in a number of ways to this specific case, but what I need is a generic TransactionAction or a different solution which let me write the actual database code, without having to write each time the same boring code.
Please do not answer "Why don't you use #Transactional annotations or AOP tx:advice configuration?" because I CAN'T!
Why? I am on Google AppEngine, and that cool guys are not so cool: the disabled access to the javax.naming package, and something in those great ways to declarative transactions touches it. :-\
You can imitate basic AOP mechanism using Proxy objects. Such as http://www.devx.com/Java/Article/21463/1954
This is a mock. But I really doubt it plays well with Spring or GAE. PLease note that you need to use interfaces for Proxies.
interface Dao {
List<Foo> getAllFoo();
}
public class MyDao implements Dao {
public MyDao() {
}
public List<Foo> getAllFoo() {
//.. get list of foo from database. No need to use transactions
}
public static void main(String[] args) {
Dao dao = new MyDao();
InvocationHandler handler = new TransactionProxyHandler(dao);
Dao proxy = (Dao) Proxy.newProxyInstance(MyDao.class.getClassLoader(), MyDao.class.getInterfaces(), handler);
List<Foo> all = proxy.getAllFoo();
}
}
class TransactionProxyHandler implements InvocationHandler {
protected Object delegate;
PlatformTransactionManager txm = new PlatformTransactionManager();
public TransactionProxyHandler(Object delegate) {
this.delegate = delegate;
}
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
TransactionStatus status = txm.getTransaction();
Object res = null;
try {
res = method.invoke(delegate, args);
txm.commit(status);
} catch (Exception e) {
e.printStackTrace();
txm.rollback(status);
}
return res;
}
}

Categories