Thursday, April 29, 2010

Unit testing with EasyMock and Spring

Let's come up with simple test scenario. I have two Spring Service implementations with corresponding interfaces. I like to test only the process method in FooServiceImp class in isolation.

The problem is FooServiceImp.peocess() calls FooBarService.process() method which I don't want to test with this peticular Unit test.

So how do I test just FooServiceImp.process() method without testing FooBarService. EasyMock is to rescue. Before the testing I can replace the reference of FooBarService to a EasyMock object and add certain expected behavior to the Mock.

Behaviors I like to add to mock:
1. The return value of the Mock service.
2. Capture the parameters passed to the Mock
Service.
3. Add a Exception to test Exception scenario

Here are the codes. Happy Unit Testing:

FooServiceTest.java

import static org.junit.Assert.*; 
import java.util.List; 
import org.easymock.Capture; 
import org.easymock.EasyMock; 
import org.junit.Before; 
import org.junit.Test; 
import org.junit.runner.RunWith; 
import org.springframework.beans.factory.annotation.Autowired; 
import org.springframework.test.context.ContextConfiguration; 
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; 


@ContextConfiguration(locations = { "classpath:Foo.xml" }) 
@RunWith(SpringJUnit4ClassRunner.class) 
public class FooServiceTest 
{ 
//Get a reference of FooServiceImp from Spring contexts 
@Autowired 
FooServiceImp fooService; 


@Before 
public void setUp() 
throws Exception 
{ 
//Replace with EasyMock object 
fooService.fooBarService = EasyMock.createNiceMock(FooBarService.class); 

} 

/* 
* Test the regular scenario 
*/ 
@Test 
public void testFooService() throws Exception{ 

//Creating a input value of String array 
String[] values = {"value1","value2", "value3"}; 

//Create Easymock Capture type to capture the 
Capture<List<String>> captureValues = new Capture<List<String>>(); 

//Setting behavior for the Mock service. 
EasyMock.expect(fooService.fooBarService.process( EasyMock.capture(captureValues))).andReturn("value1"); 

EasyMock.replay(fooService.fooBarService); 

//Test the return value 
assertEquals(fooService.process(values),"value1"); 

EasyMock.verify(fooService.fooBarService); 

//Check the parameters on Mock service call 
assertEquals(captureValues.getValue().get(0),"value1"); 


} 

/* 
* Test the Exception scenario 
*/ 
@Test(expected = Exception.class) 
public void testFooServiceException() throws Exception{ 

EasyMock.reset(fooService.fooBarService); 

String[] values = {"value1","value2", "value3"}; 

Capture<List<String>> captureValues = new Capture<List<String>>();  

//Setting the expected Exception on the Mock service 
EasyMock.expect(fooService.fooBarService.process( EasyMock.capture(captureValues))).andThrow(new Exception()); 

EasyMock.replay(fooService.fooBarService); 

//Should get an exception to pass the test 
fooService.process(values); 


} 
} 


FooService.java

public interface FooService 
{ 
public String process(String[] values) throws Exception; 
} 

FooServiceImp.java
import java.util.Arrays; 
import java.util.List; 
import org.springframework.beans.factory.annotation.Autowired; 

public class FooServiceImp 
implements FooService 
{ 

@Autowired 
FooBarService fooBarService; 

@Override 
public String process(String[] values) throws Exception 
{ 
List<string> arrayList = Arrays.asList(values); 

System.out.println(arrayList); 
return fooBarService.process((List<string>)Arrays.asList(values)); 
} 
} 

FooBarService.java
import java.util.List; 

public interface FooBarService 
{ 
public String process(List<String> values) throws Exception; 
} 

FooBarServiceImp.java:
import java.util.List; 

public class FooBarServiceImp 
implements FooBarService 
{ 
@Override 
public String process(List<String> values) throws Exception 
{ 
System.out.println("In FooBar" + values.get(0)); 
return values.get(0); 
} 
} 

Foo.xml - Spring conf file
<beans xmlns="http://www.springframework.org/schema/beans" 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
xmlns:p="http://www.springframework.org/schema/p" 
xmlns:context="http://www.springframework.org/schema/context" 
xmlns:jms="http://www.springframework.org/schema/jms" 
xmlns:amq="http://activemq.apache.org/schema/core" 
xsi:schemaLocation="http://www.springframework.org/schema/beans 
http://www.springframework.org/schema/beans/spring-beans.xsd 
http://www.springframework.org/schema/context 
http://www.springframework.org/schema/context/spring-context.xsd 
http://www.springframework.org/schema/jms 
http://www.springframework.org/schema/jms/spring-jms.xsd 
http://activemq.apache.org/schema/core 
http://activemq.apache.org/schema/core/activemq-core.xsd"> 

<bean id="fooService" primary="true" 
class="com.icrossing.service.FooServiceImp"> 
</bean> 

<bean id="fooBarService" primary="true" 
class="com.icrossing.service.FooBarServiceImp"> 
</bean> 

</beans> 

Tuesday, April 27, 2010

HibernateJMX with Spring

Hibernate Mbean is nice way to get runtime Hibernate Stat. Here is how to publish Hibernet Mbean to Tomcat Mbean server with Spring. Once Mbean are published, it can be access through Jconsole.

Tomcat setup:

 
JAVA_OPTS=" -Dcom.sun.management.jmxremote.port=9002  -Dcom.sun.management.jmxremote.authenticate=false  -Dcom.sun.management.jmxremote.ssl=false  -Djava.awt.headless=true" 


Spring config:

 
<bean id="jmxExporter" class="org.springframework.jmx.export.MBeanExporter">
<property name="beans">
<map>
<entry key="Hibernate:name=statistics">
<ref local="statisticsBean">
</ref>
</entry></map>
</property>
</bean>

<bean id="statisticsBean" class="org.hibernate.jmx.StatisticsService">
<property name="statisticsEnabled">
<value>true</value>
</property>
<!-- Change this to match you own system if needed -->
<property name="sessionFactory"><ref local="sessionFactory"></ref>
</property>
</bean>


Hibernate property:
 
<prop key="hibernate.generate_statistics">true</prop>

Tuesday, April 20, 2010

Pivot Table with SQL

One on my favourite technique with SQL is creating
pivot table. Here is an easy example using Postgres:

 
CREATE TABLE REVENUE
( YR int4,
QT chat,
REVENUE numeric);

 
insert into REVENUE values (2000, 'Q1', 240);
insert into REVENUE values (2000, 'Q2', 200);
insert into REVENUE values (2000, 'Q3', 230);
insert into REVENUE values (2000, 'Q4', 120);
insert into REVENUE values (2001, 'Q1', 320);
insert into REVENUE values (2001, 'Q2', 340);
insert into REVENUE values (2001, 'Q3', 290);
insert into REVENUE values (2001, 'Q4', 100);


Pivoting SQL:

 
SELECT
YR,
MAX(CASE WHEN QT = 'Q1' THEN REVENUE END) Q1,
MAX(CASE WHEN QT = 'Q2' THEN REVENUE END) Q2,
MAX(CASE WHEN QT = 'Q3' THEN REVENUE END) Q3,
MAX(CASE WHEN QT = 'Q4' THEN REVENUE END) Q4
FROM
REVENUE
GROUP BY YR

The result set going be pivoted
-------------------------------------------
YR  |  Q1  |  Q2  |  Q3  |  Q4
-------------------------------------------
2000   |  240   |  200    |  230    |  120
2001   |  320  |  340  |  290  |  100

Monday, April 19, 2010

Hibernate CacheMode.IGNORE option

Recently, I have ran into a hibernate related issue in our production system. We have a nightly batch program that reads a lot of rows from one table, then does some conversion and writes to a file. It brings 5000 rows in chunk, still we saw the nightly program took the server down with outOfMemory error when processing large number of rows.

After some investigation, I have found that the program brings out all the data in one session. Hibernate is holding all the objects in its session until session is closed. As a result, the GC can't clear any previous chunk of object from memory.

Since the we are reading the data for readonly purpose, we set the CacheMode.IGNORE on the Query object. It prevents Hibernate to hold the reference of the objects in it's session.

Here is snippet of the code.

Query qry = session.createQuery(query).setCacheMode(CacheMode.IGNORE);