1

我在我的项目中使用 liferay 服务构建器,现在我想测试 *Util 类。这很容易,但我不知道初始化环境的简单方法。例如,在使用 service.xml(自动生成)的 spring 配置进行 ant 测试时,我将 InitUtil.initWithSpring() 用于 init beans,但会出现以下错误:

[junit] Tests run: 1, Failures: 0, Errors: 1, Time elapsed: 2,413 sec
[junit] Tests run: 1, Failures: 0, Errors: 1, Time elapsed: 2,413 sec
[junit] 
[junit] Testcase: testJournalArticleSearch(MTest):  Caused an ERROR
[junit] BeanLocator has not been set for servlet context My-portlet
[junit] com.liferay.portal.kernel.bean.BeanLocatorException: BeanLocator has not been set for servlet context My-portlet
[junit]     at com.liferay.portal.kernel.bean.PortletBeanLocatorUtil.locate(PortletBeanLocatorUtil.java:42)
[junit]     at com.my.service.EntityLocalServiceUtil.getService(EntityLocalServiceUtil.java:70)
[junit]     at MTest.setUp(MTest.java:21)

我看过一些关于这个问题的文章,但它不起作用或者我不明白这些文章......有人知道这个问题的简单解决方案吗?

4

2 回答 2

3

我正在写这个作为答案 - 它更像是一个评论,但答案的格式选项和长度是我所追求的。

我经常看到人们在为生成的代码编写单元测试时遇到问题——而 *Util 和 servicebuilder 对我来说听起来像是生成的代码 (*LocalServiceUtil)。

我的建议是测试您的 *LocalServiceImpl 代码并相信代码生成器是正确的(或者相信代码生成器测试会在其中发现错误,但这超出了您的范围)。毕竟,servicebuilder 的 *LocalServiceUtil 类提供的功能是查找正确实现(基于 spring 配置)并委托给它的间接方法。*LocalServiceUtil 类中没有业务逻辑 - 这是在 *LocalServiceImpl 类中。

下一点是:有时即使是 *Impl 类也很难测试,因为它们会接触到需要模拟的其他服务。在这种情况下——为了保持单元测试的可读性和独立于数据库——我建议测试一层不涉及其他服务的代码。为了挑选我从这个答案中偷来的代码,我宁愿测试它,从等式中排除 UserLocalService (注意:伪代码,从未见过编译器,我正在这个输入字段中编辑)

我们要测试的代码是:

class MyUserUtil {
  public static boolean isUserFullAge(User user)  {
    Date birthday = user.getBirthday();
    long years = (System.currentTimeMillis() - birthday.getTime()) / ((long)365*24*60*60*1000);
    return years >= 18;
  }
}

我对此的测试将排除 UserLocalService:

@Test
public void testIsUserFullAge() throws Exception {
    //setup (having it here for brevity of the code sample)
    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);

    //run
    asertTrue(MyUserUtil.isUserFullAge(mockUserThatIsFullAge));
    asertFalse(MyUserUtil.isUserFullAge(mockUserThatIsNotFullAge));
}

这里的重要部分是:您的代码适用于用户对象,而不是用户 ID。因此,您不需要测试查找。如果您也非常想测试查找(例如更广泛的测试),请将其称为集成测试。但是,如果由于一些不相关的更改而经常中断,请不要抱怨。因为现在您的测试失败的原因有两个不同的来源:查找失败或您的实现不正确。您希望您的 UNIT 测试由于其中一种原因而失败,例如,当测试失败时立即知道出了什么问题,而不是开始调试。

哦,是的,该测试将在 2018 年开始失败,在现实生活中,我会测试更多的极端案例,例如明天满 18 岁或昨天这样做的人),但这是一个不同的话题。

于 2012-08-16T07:50:54.253 回答
0

我使用 Mockito 和 PowerMock 来模拟 Liferay 服务。PowerMock 允许模拟静态方法,例如XXXLocalServiceUtil. 在 Prakash K 的链接答案中,您可以找到详细描述:Testing for custom plugin portlet: BeanLocatorException and Transaction rollback for services testing

于 2012-08-16T07:51:22.730 回答