测试自定义插件portlet:BeanLocatorException和Transaction roll-back用于服务测试

我的问题:

  1. 我可以成功测试CRUD服务操作。 我正在对@Before [setUp()]进行插入并在@After [tearDown()]上删除相同的数据但是我需要支持事务而不是编写插入和删除代码。
  2. 我成功获取了我的实体的单个记录,但是当我触发搜索查询或尝试获取多个实体时,我得到:

    com.liferay.portal.kernel.bean.BeanLocatorException:尚未为servlet上下文设置BeanLocator MyCustom-portlet

我已经按照以下一些链接来设置Junit与Liferay:

  • Liferay wiki – 如何使用Junit在Portlet中测试服务
  • SO – Liferay中的unit testing
  • SO – Junit测试DAO回滚或删除

我的环境

  • Liferay 6.0.5 EE与Tomcat捆绑在一起

  • 带有Liferay IDE 1.4的Eclipse Helios使用Junit4

  • 我在eclipse中使用“ant”命令运行我的测试,但不是通过输入Alt + Shift + XT

如果我能够了解如何使用JUnit进行事务(或者至少有一些关于它如何在liferay中工作的想法)以及如何解决BeanLocatorException (或者至少为什么会抛出它),这将非常有用。 )

任何帮助将不胜感激。

我用于JUnit测试mockito框架并通过PortalBeanLocatorUtil.setBeanLocator(...) methode注入服务。 我认为使用弹簧配置显然可以做到这一点。 这里有完整的示例如何使用它。 这个例子是拍摄的,这很好,因为这种方法简单易懂。

 package mst.unittest.example; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; import org.junit.Before; import org.junit.Test; import com.liferay.portal.kernel.bean.BeanLocator; import com.liferay.portal.kernel.bean.PortalBeanLocatorUtil; import com.liferay.portal.kernel.exception.PortalException; import com.liferay.portal.kernel.exception.SystemException; import com.liferay.portal.model.User; import com.liferay.portal.service.UserLocalService; import com.liferay.portal.service.UserLocalServiceUtil; import static org.junit.Assert.*; import static org.mockito.Mockito.*; /** * @author mark.stein.ms@gmail.com */ public class MyUserUtilTest { private BeanLocator mockBeanLocator; @Before public void init() { //create mock for BeanLocator, BeanLocator is responsible for loading of Services mockBeanLocator = mock(BeanLocator.class); //... and insert it in Liferay loading infrastructure (instead of Spring configuration) PortalBeanLocatorUtil.setBeanLocator(mockBeanLocator); } @Test public void testIsUserFullAge() throws PortalException, SystemException, ParseException { //setup SimpleDateFormat format = new SimpleDateFormat("yyyy_MM_dd"); Date D2000_01_01 = format.parse("2000_01_01"); Date D1990_06_30 = format.parse("1990_06_30"); UserLocalService mockUserLocalService = mock(UserLocalService.class); User mockUserThatIsFullAge = mock(User.class); when(mockUserThatIsFullAge.getBirthday()).thenReturn(D1990_06_30); User mockUserThatIsNotFullAge = mock(User.class); when(mockUserThatIsNotFullAge.getBirthday()).thenReturn(D2000_01_01); //overwrite getUser(...) methode so that wir get mock user-object with mocked behavior when(mockUserLocalService.getUser(1234567)).thenReturn(mockUserThatIsFullAge); when(mockUserLocalService.getUser(7654321)).thenReturn(mockUserThatIsNotFullAge); //load our mock-object instead of default UserLocalService when(mockBeanLocator.locate("com.liferay.portal.service.UserLocalService")).thenReturn(mockUserLocalService); //run User userFullAge = UserLocalServiceUtil.getUser(1234567); boolean fullAge = MyUserUtil.isUserFullAge(userFullAge); //verify assertTrue(fullAge); //run User userNotFullAge = UserLocalServiceUtil.getUser(7654321); boolean notfullAge = MyUserUtil.isUserFullAge(userNotFullAge); //verify assertFalse(notfullAge); } } class MyUserUtil { public static boolean isUserFullAge(User user) throws PortalException, SystemException { Date birthday = user.getBirthday(); long years = (System.currentTimeMillis() - birthday.getTime()) / ((long)365*24*60*60*1000); return years > 18; } } 

你也可以在没有mockito框架的情况下使用这种方法,然后你必须手动创建像MockBeanLocator这样的模拟类。

使用PowerMock的方法

使用PowerMock,您可以放弃BeanLocator因为PowerMock允许覆盖静态方法。 这是与PowerMock相同的示例:

 package mst.unittest.example; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; import org.junit.Test; import org.junit.runner.RunWith; import org.powermock.api.mockito.PowerMockito; import org.powermock.core.classloader.annotations.PrepareForTest; import org.powermock.modules.junit4.PowerMockRunner; import com.liferay.portal.kernel.exception.PortalException; import com.liferay.portal.kernel.exception.SystemException; import com.liferay.portal.model.User; import com.liferay.portal.service.UserLocalServiceUtil; import static org.junit.Assert.*; import static org.mockito.Mockito.*; /** * @author Mark Stein * */ @RunWith(PowerMockRunner.class) @PrepareForTest(UserLocalServiceUtil.class) public class LiferayAndPowerMockTest { @Test public void testIsUserFullAge() throws PortalException, SystemException, ParseException { //setup SimpleDateFormat format = new SimpleDateFormat("yyyy_MM_dd"); Date D2000_01_01 = format.parse("2000_01_01"); Date D1990_06_30 = format.parse("1990_06_30"); User mockUserThatIsFullAge = mock(User.class); when(mockUserThatIsFullAge.getBirthday()).thenReturn(D1990_06_30); User mockUserThatIsNotFullAge = mock(User.class); when(mockUserThatIsNotFullAge.getBirthday()).thenReturn(D2000_01_01); //overwrite getUser(...) by UserLocalServiceUtil methode so that wir get mock user-object with mocked behavior PowerMockito.mockStatic(UserLocalServiceUtil.class); when(UserLocalServiceUtil.getUser(1234567)).thenReturn(mockUserThatIsFullAge); when(UserLocalServiceUtil.getUser(7654321)).thenReturn(mockUserThatIsNotFullAge); //run boolean fullAge = MySecUserUtil.isUserFullAge(1234567); //verify assertTrue(fullAge); //run boolean notfullAge = MySecUserUtil.isUserFullAge(7654321); //verify assertFalse(notfullAge); } } class MySecUserUtil { public static boolean isUserFullAge(long userId) throws PortalException, SystemException { User user = UserLocalServiceUtil.getUser(userId); Date birthday = user.getBirthday(); long years = (System.currentTimeMillis() - birthday.getTime()) / ((long)365*24*60*60*1000); return years > 18; } } 

在这里,您发现PowerMock 1.4.12包含Mockito和JUnit,包括依赖项http://code.google.com/p/powermock/downloads/detail?name=powermock-mockito-junit-1.4.12.zip&can=2&q=

猜测:你真的需要测试交易吗? 或者只是围绕数据库访问的业务逻辑? 因为如果是这样,你可以尝试用EasyMock(或类似的)编写unit testing,避免访问数据库而测试function