Java 使用Mockito、TestNG和OpenEJB对EJB进行单元测试

Java 使用Mockito、TestNG和OpenEJB对EJB进行单元测试,java,ejb,testng,mockito,openejb,Java,Ejb,Testng,Mockito,Openejb,我有以下EJB: PersonService.java PersonServiceImpl.java RemotePersonService.java PersonServiceTest.java 现在,我想做的是用Mockito的mock替换PersonServiceImpl.java中的RemotePersonService实现,并且在我的testPersonService方法中仍然有相同的调用 我试过: PersonServiceTest.java @LocalClient 公共类Per

我有以下EJB:

PersonService.java

PersonServiceImpl.java

RemotePersonService.java

PersonServiceTest.java


现在,我想做的是用Mockito的mock替换PersonServiceImpl.java中的RemotePersonService实现,并且在我的testPersonService方法中仍然有相同的调用

我试过:

PersonServiceTest.java

@LocalClient
公共类PersonServiceTest扩展了AbstractTest{
@嘲弄
专用RemotePersonService RemotePersonService;
@EJB
@注射模拟
私人私人服务;
@BeforeMethod(alwaysRun=true)
公共void setUpMocks(){
initMocks(this);
List customResults=new ArrayList();
customResults.add(新人(“Alice”);
customResults.add(新用户(“Bob”);
Mockito.when(remotePersonService.getAllPersons())。然后返回(customResults);
}
@试验
公共void testPersonService(){
long count=personService.countPersons();
Assert.assertEquals(计数,2l);
}
}
但这不起作用。@Mock-RemotePersonService没有注入PersonService,并且仍然使用真正的EJB


我如何才能做到这一点?

不要在测试中使用注释。有一个将连接所有依赖项的构造函数

@Stateless
public class PersonServiceImpl implements PersonService {

    @EJB
    private RemotePersonService remotePersonService;

    // Let your test instantiate a mock service and wire it into your test instance using this constructor.
    public PersonServiceImpl(RemotePersonService rps) {
        this.remotePersonService = rps;
    }

    @Override
    public long countPersons() {
         return remotePersonService.getAllPersons().size();
    }
}
创建模拟并将其传递给它。您的测试可能如下所示:

@LocalClient
public class PersonServiceTest extends AbstractTest {

    @Test
    public void testPersonService() {
        RemotePersonService mockRemotePersonService = Mockito.mock(RemotePersonService.class);
        List<Person> customResults = new ArrayList<Person>();
        customResults.add(new Person("Alice"));
        customResults.add(new Person("Bob"));
              Mockito.when(mockRemotePersonService.getAllPersons()).thenReturn(customResults);
        PersonService personService = new PersonServiceImpl(mockRemotePersonService);
        long count = personService.countPersons();    
        Assert.assertEquals(count, 2l);
    }
}
@LocalClient
公共类PersonServiceTest扩展了AbstractTest{
@试验
公共void testPersonService(){
RemotePersonService mockRemotePersonService=Mockito.mock(RemotePersonService.class);
List customResults=new ArrayList();
customResults.add(新人(“Alice”);
customResults.add(新用户(“Bob”);
Mockito.when(mockRemotePersonService.getAllPersons())。然后返回(customResults);
PersonService PersonService=新PersonService MPL(mockRemotePersonService);
long count=personService.countPersons();
Assert.assertEquals(计数,2l);
}
}

我在类上使用setter,并查找ejb

      private ServicioAsyncMessaging servicioNotificaciones;
我删除getter上的@EJB-->和

    public ServicioAsyncMessaging getServicioNotificaciones() {
            if(servicioNotificaciones == null){
             servicioNotificaciones = (ServicioAsyncMessaging)Lookup.getEjb(EjbJndiConstantes.EJB_SERVICIO_ASYNC_MSG);
            }
            return servicioNotificaciones;
        }
    
        public void setServicioNotificaciones(ServicioAsyncMessaging servicioNotificaciones) {
            this.servicioNotificaciones = servicioNotificaciones;
        }
查找结果包括:

public static Object getEjb(String lookupName){
    Object t = null;
    try {
        Context ctx = new InitialContext();
         t=  ctx.lookup(lookupName);
    } catch (NamingException e) {
        log.error("getEjb | Error {}",e.getMessage(),e);
    }
    return t;
}

通过这些更改,mockito-->在setter上注入mock。

不要在测试中使用注释。有一个将连接所有依赖项的构造函数。创建模拟并将其传递给它。在PersonService测试中将PersonService类型更改为PersonServiceImpl显然可以做到这一点。但是,难道不能使用接口而不是实现吗?这里应该明确说明。如果使用
PersonService
如何知道注入了哪个实现并进行了测试?使用
PersonServiceImpl
可以告诉您这一点。但这就是问题所在-您不必知道注入的类型。不允许@InjectMock注入接口,因为您应该测试的是具体类而不是接口。因此,正如您之前所评论的,您应该用一个具体的类替换mock被注入的接口,这是行不通的,因为PersonService是一个接口,您不能实例化它们。此外,编写构造函数或setter仅用于单元测试以注入mock,这只是一点开销,因为可以使用注释注入它们;应该是PersonServiceImpl。你可以举例说明。不是开销——微不足道。注释也必须实例化对象。有争议的是,处理注释比简单地实例化依赖项的开销更大。关键是他无法让它与注释一起工作。这将起作用。使用PersonServiceImpl他可以让它与anotations一起工作(因为他说他已经开始工作了)。“在PersonServiceTest中将类型PersonService更改为PersonServiceImpl显然起到了作用。”-显然是的。我可以在测试中使用具体的类PersonServiceImpl使其工作,但我想知道是否有可能改用这个接口。但显然,由于Mockito是如何注入mocks的,所以这样做从本质上来说是不可能的。
@LocalClient
public class PersonServiceTest extends AbstractTest {

    @EJB
    private PersonService personService;

    @Test
    public void testPersonService() {
        long count = personService.countPersons();

        Assert.assertEquals(count, 1l);
    }
}
@LocalClient
public class PersonServiceTest extends AbstractTest {

    @Mock
    private RemotePersonService remotePersonService;

    @EJB
    @InjectMocks
    private PersonService personService;

    @BeforeMethod(alwaysRun = true)
    public void setUpMocks() {
        MockitoAnnotations.initMocks(this);

        List<Person> customResults = new ArrayList<Person>();
        customResults.add(new Person("Alice"));
        customResults.add(new Person("Bob"));

        Mockito.when(remotePersonService.getAllPersons()).thenReturn(customResults);
    }

    @Test
    public void testPersonService() {
        long count = personService.countPersons();

        Assert.assertEquals(count, 2l);
    }
}
@Stateless
public class PersonServiceImpl implements PersonService {

    @EJB
    private RemotePersonService remotePersonService;

    // Let your test instantiate a mock service and wire it into your test instance using this constructor.
    public PersonServiceImpl(RemotePersonService rps) {
        this.remotePersonService = rps;
    }

    @Override
    public long countPersons() {
         return remotePersonService.getAllPersons().size();
    }
}
@LocalClient
public class PersonServiceTest extends AbstractTest {

    @Test
    public void testPersonService() {
        RemotePersonService mockRemotePersonService = Mockito.mock(RemotePersonService.class);
        List<Person> customResults = new ArrayList<Person>();
        customResults.add(new Person("Alice"));
        customResults.add(new Person("Bob"));
              Mockito.when(mockRemotePersonService.getAllPersons()).thenReturn(customResults);
        PersonService personService = new PersonServiceImpl(mockRemotePersonService);
        long count = personService.countPersons();    
        Assert.assertEquals(count, 2l);
    }
}
      private ServicioAsyncMessaging servicioNotificaciones;
    public ServicioAsyncMessaging getServicioNotificaciones() {
            if(servicioNotificaciones == null){
             servicioNotificaciones = (ServicioAsyncMessaging)Lookup.getEjb(EjbJndiConstantes.EJB_SERVICIO_ASYNC_MSG);
            }
            return servicioNotificaciones;
        }
    
        public void setServicioNotificaciones(ServicioAsyncMessaging servicioNotificaciones) {
            this.servicioNotificaciones = servicioNotificaciones;
        }
public static Object getEjb(String lookupName){
    Object t = null;
    try {
        Context ctx = new InitialContext();
         t=  ctx.lookup(lookupName);
    } catch (NamingException e) {
        log.error("getEjb | Error {}",e.getMessage(),e);
    }
    return t;
}