【问题标题】:Eclipse Scout Neon mock backend serviceEclipse Scout Neon 模拟后端服务
【发布时间】:2016-07-08 00:48:23
【问题描述】:

在我们的项目中,我有模块 scout.client、scout.server、scout.shared 和 backend。

Backend 对 scout.server 和 scout.shared 没有依赖关系,但 scout.server 对后端有依赖关系。

在后端项目内部,我拥有所有业务逻辑并调用所有外部服务。

我的问题是当我尝试测试使用后端服务的侦察服务时。

因为 scout 提供了一些很好的模拟 bean 的工具,我们将后端内部的服务定义为 bean:

 BEANS.getBeanManager().registerClass(CarService.class);
 BEANS.getBeanManager().registerClass(PartnerService.class);

CarService.class 和 PartnerService.class 都在后端。

当我尝试编写一些测试并将@BeanMock 添加到测试中的服务时

@BeanMock
private IPartnerService partnerService;

我得到了模拟,但是每个函数的每个返回都是空的,即使我写了

doReturn(PartnerBuilder.standardPartnerListWithOneElement()).when(this.partnerService)
    .getPartners(any(Set.class));

如果我在测试中进行调试,在使用调试器调用此测试之前,我可以获得:

  partnerService.getPartners(...) -> return a list of person 

什么是正确的,但是当被测试的类调用此服务时,它返回 null。

我知道这可能是由于接口@ApplicationScoped 上缺少注释。如果没有这个,就不能保证只创建一个bean,并且when 语句会对该bean 的另一个副本做出反应......?

我无法在接口上添加注释,因为后端对侦察模块没有依赖关系。

我该如何处理这种情况?


测试类是:

 public class UtilityPartner {

  /**
   * Method return service bean for getting partners by ids.
   *
   * @return
   */
   private static IPartnerService getPartnerService() {

    return BEANS.get(IPartnerService.class);
   }

  public static String getPartnerName(final Long partnerId) {

    if (partnerId == null) {
      return "";
    }

    final List<Partner> partners =
        (List<Partner>) getPartnerService().getPartners(Sets.newHashSet(partnerId));
    if (partners == null || partners.isEmpty()) {
      return "";
    }
    final Partner partner = partners.get(0);
    return LookupUtil.createLookupDescription(partner.getId(), partner.getName());
  }

}

测试类是:

 @RunWith(ServerTestRunner.class)
 @RunWithSubject("anonymous")
 @RunWithServerSession(ServerSession.class)
 public class TestUtilityPartner {

    @BeanMock
    private IPartnerService partnerService;

     @Before
     public void init() {
         doReturn(PartnerBuilder.standardPartnerListWithOneElement()).when(this.partnerService).getPartners(any(Set.class));

     }

     @Test
     public void getPartnerName() {

        final String name = UtilityPartner.getPartnerName(10L);
        Assert.assertEquals("My name", name); // NAME IS ""
     }
}

【问题讨论】:

    标签: eclipse-scout


    【解决方案1】:

    在这里使用@BeanMock 没有帮助,因为您没有使用应用程序范围的服务:

    在 init 方法中,您正在更改本地字段 partnerService。但是,在您的测试中,您调用 UtilityPartner.getPartnerService,它正在创建一个新实例(使用BEANS.get(IPartnerService.class))。

    @BeanMock 更便于模拟应用程序范围的 bean。

    您始终可以手动注册您的 bean as shown by Jmini。请不要忘记在测试后再次注销bean!

    我们建议使用org.eclipse.scout.rt.testing.shared.TestingUtility.registerBean(BeanMetaData),它会自动添加测试订单并删除@TunnelToServer 注释。

    【讨论】:

      【解决方案2】:

      我认为您应该在 Bean 管理器中注册您的模拟实例(请参阅 Scout 架构文档中的 bean registration)。您应该使用小订单 (-10 000 is recommended for tests),以便您的模拟赢得高效注册。最好的方法是使用TestingUtility 类来注册/注销你的模拟。不要忘记调用unregisterBean()方法(在@After注解的方法中):

      import java.util.Collections;
      
      import org.eclipse.scout.rt.platform.BeanMetaData;
      import org.eclipse.scout.rt.platform.IBean;
      import org.eclipse.scout.rt.testing.shared.TestingUtility;
      import org.junit.After;
      import org.junit.Assert;
      import org.junit.Before;
      import org.junit.Test;
      import org.mockito.Mockito;
      
      public class TestUtilityPartner {
      
          private IBean<?> beanRegistration;
      
          @Before
          public void init() {
              partnerService = Mockito.mock(IPartnerService.class);
      
              // Register the mock using the Bean meta information:
              BeanMetaData beanData = new BeanMetaData(IPartnerService.class)
                 .withInitialInstance(partnerService)
                 .withApplicationScoped(true);
              this.beanRegistration = TestingUtility.registerBean(beanData);
      
      
             // Mockito behavior:
             Mockito.doReturn(Collections.singletonList(new Partner(34L, "John Smith")))
                 .when(partnerService).getPartners(Mockito.any(Set.class));
          }
      
          @After
          public void after() {
              // Unregister the mocked services:
              TestingUtility.unregisterBean(this.beanRegistration);
          }
      
          @Test
          public void getPartnerName() {
              String name = UtilityPartner.getPartnerName(10L);
              Assert.assertEquals("10 - John Smith", name);
          }
      }
      

      我不确定@BeanMock (org.eclipse.scout.rt.testing.platform.mock.BeanMock) 在做什么,但根据Judith Gull's answer 它不会起作用:

      在这里使用@BeanMock 没有帮助,因为您没有使用应用程序范围的服务:

      在 init 方法中,您正在更改本地字段 partnerService。但是,在您的测试中,您调用 UtilityPartner.getPartnerService,它正在创建一个新实例(使用BEANS.get(IPartnerService.class))。

      @BeanMock 更便于模拟应用程序范围的 bean。

      【讨论】:

      • 哇这个工作!我还有一个问题:当我注册我的 bean(不是在测试中,而是在 PlatformListener 中)时,按照您在此处发布的注册 BEAN 会更好吗?
      • 我无法在评论中回答这个问题。将您的第二个问题移至另一个线程:stackoverflow.com/questions/36164077/…
      • 我已将示例更新为使用TestingUtility。你应该更新你的代码。
      猜你喜欢
      • 2023-03-18
      • 2016-04-24
      • 1970-01-01
      • 2016-06-29
      • 1970-01-01
      • 2016-10-08
      • 2016-09-22
      • 2016-06-29
      • 1970-01-01
      相关资源
      最近更新 更多