2012-03-14 63 views
10

我的问题:测试自定义插件的portlet:BeanLocatorException和事务回滚的服务测试

  1. 我可以成功测试CRUD操作服务。我是做 上@Before插入[设置()]和@After 同一数据的删除[拆解()],但展望未来,我需要支持事务 而不是插入和删除编写代码。
  2. 我成功地获取我的实体的单记录,但是当我火了搜索查询或尝试获取我的实体,我得到的不止一个:

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

我遵循以下一些环节,以建立与Junit的Liferay的:

我的环境

  • 的Liferay 6.0.5 EE捆绑的Tomcat

  • 的Eclipse太阳神与被判无期徒刑AY使用Junit4

  • 我正在我的测试,在Eclipse本身 “蚁族” 的命令,但不 IDE 1.4通过键入Alt键 + + X牛逼

这将是非常有益的,如果我能得到一些想法,如何去使用的交易使用JUnit(或至少一些想法,它是如何工作的Liferay),以及如何解决BeanLocatorException(或至少为什么会被抛出)

任何帮助将不胜感激。

+0

人在那里谁知道一些关于如何交易的Liferay在测试用例工作不一定,甚至一个小提示将是有用的或URL或电子书。谢谢 – 2012-05-04 05:49:47

回答

4

我用于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 [email protected] 
*/ 
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=

+0

非常感谢!这给了我这个单元测试的东西的阳光。那么,如果我使用我的'com.prakash.MyLocalService'类而不是'com.liferay.portal.service.UserLocalService',这个工作将会如何?我会试试这个,让你知道。再次感谢! – 2012-08-08 04:35:24

+0

是的,你也可以为自己的服务做到这一点,但你需要使用'PortletBeanLocatorUtil'而不是'PortalBeanLocatorUtil',或者为Mockito添加PowerMock并直接模拟'com.prakash.MyLocalServiceUtil'类 – Mark 2012-08-08 08:11:22

+0

太棒了!谢谢!如果你可以在你的答案中包含这些信息,那将是非常好的。谢谢马克。 – 2012-08-08 08:26:22

2

猜测:你真的需要测试的交易?或者只是关于数据库访问的业务逻辑? 因为如果是这样,你可以尝试用EasyMock(或类似的)编写单元测试,避免访问数据库,但仍然测试功能

+0

会试试看。感谢您的建议。我确实需要测试交易,但我想可以等待:-)。你有没有使用Liferay的想法? – 2012-06-22 04:58:38

+0

你是否在为你的实体使用ServiceBuilder?如果是这样,我认为(不是100%肯定)你不能这样做。我对Liferay的经历告诉我,每次打电话给你的服务都是一次交易。甚至连Liferay都以这种方式在后端工作。如果我是你,我会尝试建立自己的Spring上下文(而不是Liferay的),设置Hibernate(你可以使用liferay的数据源)并从那里开始。使用@Transactional方面设计您的服务并测试您的交易 – gcesarmza 2012-06-25 15:46:01

+0

我正在使用liferay的Service Builder。 “我对Liferay的经验告诉我,你对服务进行的每一个调用都是一个事务” - 通过* ServiceUtil类调用,然后是。但是我们可以通过可用的*服务实例调用多种服务方法。我在想Service builder使用Spring Context和hibernate。 – 2012-06-26 04:46:20