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

Unit testing an EJB with Mockito, TestNG and OpenEJB

我有以下 EJB:

PersonService.java

@Local
public interface PersonService {
    long countPersons();
}

PersonServiceImpl.java

@Stateless
public class PersonServiceImpl implements PersonService {

    @EJB
    private RemotePersonService remotePersonService;

    @Override
    public long countPersons() {
         return remotePersonService.getAllPersons().size();
    }
}

远程PersonService.java

@Local
public interface RemotePersonService {
    List<Person> getAllPersons();
}

RemotePersonServiceImpl.Java

@Stateless
public class RemotePersonServiceImpl {
    @Override
    public List<Person> getAllPersons() {
        // Here, I normally call a remote webservice, but this is for the purpose of this question
        List<Person> results = new ArrayList<Person>();
        results.add(new Person("John"));
        return results;
    }
}

这是我的测试

AbstractTest.java

public abstract class AbstractTest {

    private InitialContext context;

    @BeforeClass(alwaysRun = true)
    public void setUp() throws Exception {
        System.setProperty("java.naming.factory.initial", "org.apache.openejb.client.LocalInitialContextFactory");

        Properties properties = new Properties();
        properties.load(getClass().getResourceAsStream("/unittest-jndi.properties"));

        context = new InitialContext(properties);
        context.bind("inject", this);

    }

    @AfterClass(alwaysRun = true)
    public void tearDown() throws Exception {
        if (context != null) {
            context.close();
        }
    }
}

PersonServiceTest.java

@LocalClient
public class PersonServiceTest extends AbstractTest {

    @EJB
    private PersonService personService;

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

        Assert.assertEquals(count, 1l);
    }
}

现在,我想要做的是用 Mockito 的模拟替换 PersonServiceImpl.java 中的 RemotePersonService 实现,并且在我的 [=43] 中仍然有相同的调用=]testPersonService 方法。

我试过了:

PersonServiceTest.java

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

但这行不通。 PersonService中没有注入@Mock RemotePersonService,依然使用真正的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);
    }
}

我在 class 上使用 setters,并查找 ejb

      private ServicioAsyncMessaging servicioNotificaciones;

我删除了@EJB --> 和 getter

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

查找 es:

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 上注入模拟。