Does anyone know how to run unit tests for Liferay portlets? I have found a lot of posts about it (e.g. http://agile-reflections.opnworks.com/2010/06/portlet-unit-testing-wi
This may be overkill, but if you're looking for an Enterprise approach with continuous integration testing, this blog gives a very good example: Continuous integration on Liferay: running your Selenium 2 tests on the Tomcat 6 bundle
You need to have some third party libraries on classpath.
THe key point is having even portal-impl.jar and other portal dependencies on classpath and having InitUtil.initWithSpring(boolean);
load up core spring xml configs that you specify in spring-ext.properties in spring.congigs property, only those services you need. You may need no portal services and only the portlet ones, but this is a problem because your portlet services generated by service builder use the portal services.
Using service builder just needs good knowledge of spring and classloading.
But you need to understand the infrastructure before doing that. There are quite a lot of hacks needed... Like
BeanLocator beanLocator = new BeanLocatorImpl(PortalClassLoaderUtil.getClassLoader(), ac);
PortletBeanLocatorUtil.setBeanLocator("portlet", beanLocator);
Unit testing Liferay portlets is quite complicated when ServiceBuilder is utilized.
The reason is that it generates quite heavy services that contain references not only to beans within Portlet, but even to the Portal beans generated by ServiceBuilder.
There are tools like InitUtil.init(); that lets you at least instantiate and use ServiceBuilder entities... not EntityServices though. For that you'd have to use SpringUtil.loadContext(); that requires
System.setProperty("external-properties", "testing.properties");
where testing.properties contains :
spring.configs=META-INF/ext-spring.xml,\
META-INF/base-spring.xml,\
META-INF/dynamic-data-source-spring.xml,\
META-INF/infrastructure-spring.xml,\
META-INF/shard-data-source-spring.xml,\
META-INF/hibernate-spring.xml,\
META-INF/portlet-spring.xml
These are spring definitions to be loaded for testing application context. It all would be OK, but beans from portlet-spring.xml are those heavy services containing references to Portal bean definitions like ResourceService, UserLocalService, CounterLocalService and you would have to load even META-INF/portal-spring.xml
and trust me, it's not that easy cause then you'd have to load quite a lot of other stuff.
THE ANSWER:
The truth is, that you most likely won't have to unit test portlet SB services, never. They represent entities with persistence and service layer around. Something that is not to be tested. You just have to mock them and stub their methods, right ?
And the best way for junit and integration testing as to mocking is not using *LocalServiceUtil static classes in your application, because it is almost unmockable.
You just need to create a Spring FactoryBean :
public class PortalFactoryBean implements FactoryBean {
private Class type;
public void setType(final Class type) {
this.type = type;
}
@Override
public Object getObject() throws Exception {
return PortalBeanLocatorUtil.locate(type.getName());
}
@Override
public Class getObjectType() {
return type;
}
}
public class PortletFactoryBean implements FactoryBean {
private Class type;
public void setType(final Class type) {
this.type = type;
}
@Override
public Object getObject() throws Exception {
return PortletBeanLocatorUtil.locate(type.getName());
}
@Override
public Class getObjectType() {
return type;
}
}
<bean id="somePortalBean" class="example.spring.PortalFactoryBean" lazy-init="true">
<property name="type" value="com.liferay.some.util.SomeService"/>
</bean>
<bean id="somePortletBean" class="example.spring.PortletFactoryBean" lazy-init="true">
<property name="type" value="com.example.SomeService"/>
</bean>
@Autowired
private SomeService somePortalBean;
Writing unit/integration tests for this portlet would be quite easy, right ? You just create a spring context for testing and you mock these services :
Using Service Builder is worth it, but you must have some Spring knowledge and play with it for some time. Then it spares a lot of time because it is easy to maintain.