Eclipse Scout Neon mock backend service

帅比萌擦擦* 提交于 2019-12-24 13:08:01

问题


In our project I have modules scout.client, scout.server, scout.shared and backend.

Backend has no dependencies to scout.server and scout.shared, but scout.server has dependencies to backend.

Inside backend project I have all business logic and calling all outside services.

My problem is when I try to test scout services that use some service from backend.

Because scout provide some great tool for mocking beans, we defined our service inside backend as beans as :

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

Both, CarService.class and PartnerService.class are in backend.

When I try to write some tests and I add @BeanMock to service in test

@BeanMock
private IPartnerService partnerService;

I get mock, but then every return every function is null, even if I write

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

If I debug in my test, before this test is called with debugger I can get :

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

what is right, but when class that is tested calles this service it return null.

I understand that this could be due to missing annotation on interface @ApplicationScoped. Without this there is no guarantee that only one bean is created, and when statement react on another copy of that bean...?

I could not add annotation on interface because backend has no dependencies to scout modules.

How could I handle this kind of cases?


Tested class is :

 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());
  }

}

test class is :

 @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 ""
     }
}

回答1:


I think that you should register your mock instance in the Bean manager (See bean registration in the Scout Architecture Document). You should use a small order (-10 000 is recommended for tests), in order for your mock to win over the productive registration. The best approach is to use the TestingUtility class to register/unregister your mock. Do not forget to call the unregisterBean() method (in the method annotated with @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);
    }
}

I am not sure what @BeanMock (org.eclipse.scout.rt.testing.platform.mock.BeanMock) is doing, but according to Judith Gull's answer it will not work:

Using @BeanMock does not help here, because you are not using an application scoped service:

In the init method you are changing the local field partnerService. However, in your test you call UtilityPartner.getPartnerService, which is creating a new instance (with BEANS.get(IPartnerService.class)).

@BeanMock is more useful for convenience for mocking application scoped beans.




回答2:


Using @BeanMock does not help here, because you are not using an application scoped service:

In the init method you are changing the local field partnerService. However, in your test you call UtilityPartner.getPartnerService, which is creating a new instance (with BEANS.get(IPartnerService.class)).

@BeanMock is more useful for convenience for mocking application scoped beans.

You can always register your beans manually as shown by Jmini. Please do not forget to unregister the bean again after the test!

We recommend using org.eclipse.scout.rt.testing.shared.TestingUtility.registerBean(BeanMetaData), which is automatically adding a testing order and removing @TunnelToServer annotations.



来源:https://stackoverflow.com/questions/36132254/eclipse-scout-neon-mock-backend-service

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!