如何在 JUnit 测试中使用 HK2 注入 CDI 事件?
How can I inject CDI event with HK2 in JUnit Test?
我想用简单的 JUnit 测试(没有 arquillian,没有 MicroShed)来测试我的 Jakarta 应用程序 (Payara)。
我使用 Hk2 的 ServiceLocator 来注入服务,它对我的 JPA 实体和服务运行良好。
private static ServiceLocator serviceLocator;
@BeforeAll
public static void setUpBeforeClass() {
serviceLocator = ServiceLocatorUtilities.createAndPopulateServiceLocator();
ServiceLocatorUtilities.addClasses(
serviceLocator,
EntityManagerHK2Factory.class,
ProducerUtils.class,
FishService.class,
ShopRepository.class,
Family.class, Fish.class, FishStockKey.class, Shop.class, Stock.class, WaterType.class);
}
@Test
public void it_should_sell_fish() {
//GIVEN
FishService fishService = serviceLocator.getService(FishService.class);
String shopName = "Magic Fish";
String fishName = "Scalaire";
int quantity = 3;
//WHEN
float bill = fishService.sell(shopName, fishName, quantity);
//THEN
assertThat(bill, is(54f));
}
但是我有一些问题,因为我在我的 FishService 中包含了 CDI 事件。
@Inject
private Event<StockEvent> stockEvent;
然后我触发一个事件。
当我启动测试 serviceLocator 时,无法创建 FishService,并且出现以下错误:
A MultiException has 3 exceptions. They are:
1. org.glassfish.hk2.api.UnsatisfiedDependencyException: There was no object available for injection at SystemInjecteeImpl(requiredType=Event<StockEvent>,parent=FishService,qualifiers={},position=-1,optional=false,self=false,unqualified=null,976949492)
2. java.lang.IllegalArgumentException: While attempting to resolve the dependencies of com.meynier.jakarta.service.FishService errors were found
3. java.lang.IllegalStateException: Unable to perform operation: resolve on com.meynier.jakarta.service.FishService
在此测试中class我不想测试事件 CDI 功能。
如何使用 Hk2 注入 CDI 事件服务?
(我的代码在这个 github account 中)
您可以使用 Mockito 模拟 Event
,然后将模拟与 AbstractBinder
绑定并将其添加到 ServiceLocator
。这是一个完整的测试
import javax.inject.Inject;
import org.glassfish.hk2.api.ServiceLocator;
import org.glassfish.hk2.api.TypeLiteral;
import org.glassfish.hk2.utilities.Binder;
import org.glassfish.hk2.utilities.ServiceLocatorUtilities;
import org.glassfish.hk2.utilities.binding.AbstractBinder;
import org.junit.BeforeClass;
import org.junit.Test;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
public class Hk2CdiInjectTest {
public interface Event<T> {
T get();
}
public interface StockEvent {
String getStock();
}
public static class Service {
@Inject
private Event<StockEvent> event;
public String getStock() {
return event.get().getStock();
}
}
private static ServiceLocator locator;
@BeforeClass
public static void setUpBeforeClass() {
locator = ServiceLocatorUtilities.createAndPopulateServiceLocator();
ServiceLocatorUtilities.addClasses(locator, Service.class);
final Event<StockEvent> event = (Event<StockEvent>) mock(Event.class);
final StockEvent stockEvent = mock(StockEvent.class);
when(stockEvent.getStock()).thenReturn("GOOGL UP!");
when(event.get()).thenReturn(stockEvent);
Binder eventBinder = new AbstractBinder() {
@Override
public void configure() {
bind(event).to(new TypeLiteral<Event<StockEvent>>() {});
}
};
ServiceLocatorUtilities.bind(locator, eventBinder);
}
@Test
public void testIt() {
Service service = locator.getService(Service.class);
assertThat(service.getStock()).isEqualTo("GOOGL UP!");
}
}
我想用简单的 JUnit 测试(没有 arquillian,没有 MicroShed)来测试我的 Jakarta 应用程序 (Payara)。
我使用 Hk2 的 ServiceLocator 来注入服务,它对我的 JPA 实体和服务运行良好。
private static ServiceLocator serviceLocator;
@BeforeAll
public static void setUpBeforeClass() {
serviceLocator = ServiceLocatorUtilities.createAndPopulateServiceLocator();
ServiceLocatorUtilities.addClasses(
serviceLocator,
EntityManagerHK2Factory.class,
ProducerUtils.class,
FishService.class,
ShopRepository.class,
Family.class, Fish.class, FishStockKey.class, Shop.class, Stock.class, WaterType.class);
}
@Test
public void it_should_sell_fish() {
//GIVEN
FishService fishService = serviceLocator.getService(FishService.class);
String shopName = "Magic Fish";
String fishName = "Scalaire";
int quantity = 3;
//WHEN
float bill = fishService.sell(shopName, fishName, quantity);
//THEN
assertThat(bill, is(54f));
}
但是我有一些问题,因为我在我的 FishService 中包含了 CDI 事件。
@Inject
private Event<StockEvent> stockEvent;
然后我触发一个事件。
当我启动测试 serviceLocator 时,无法创建 FishService,并且出现以下错误:
A MultiException has 3 exceptions. They are:
1. org.glassfish.hk2.api.UnsatisfiedDependencyException: There was no object available for injection at SystemInjecteeImpl(requiredType=Event<StockEvent>,parent=FishService,qualifiers={},position=-1,optional=false,self=false,unqualified=null,976949492)
2. java.lang.IllegalArgumentException: While attempting to resolve the dependencies of com.meynier.jakarta.service.FishService errors were found
3. java.lang.IllegalStateException: Unable to perform operation: resolve on com.meynier.jakarta.service.FishService
在此测试中class我不想测试事件 CDI 功能。
如何使用 Hk2 注入 CDI 事件服务? (我的代码在这个 github account 中)
您可以使用 Mockito 模拟 Event
,然后将模拟与 AbstractBinder
绑定并将其添加到 ServiceLocator
。这是一个完整的测试
import javax.inject.Inject;
import org.glassfish.hk2.api.ServiceLocator;
import org.glassfish.hk2.api.TypeLiteral;
import org.glassfish.hk2.utilities.Binder;
import org.glassfish.hk2.utilities.ServiceLocatorUtilities;
import org.glassfish.hk2.utilities.binding.AbstractBinder;
import org.junit.BeforeClass;
import org.junit.Test;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
public class Hk2CdiInjectTest {
public interface Event<T> {
T get();
}
public interface StockEvent {
String getStock();
}
public static class Service {
@Inject
private Event<StockEvent> event;
public String getStock() {
return event.get().getStock();
}
}
private static ServiceLocator locator;
@BeforeClass
public static void setUpBeforeClass() {
locator = ServiceLocatorUtilities.createAndPopulateServiceLocator();
ServiceLocatorUtilities.addClasses(locator, Service.class);
final Event<StockEvent> event = (Event<StockEvent>) mock(Event.class);
final StockEvent stockEvent = mock(StockEvent.class);
when(stockEvent.getStock()).thenReturn("GOOGL UP!");
when(event.get()).thenReturn(stockEvent);
Binder eventBinder = new AbstractBinder() {
@Override
public void configure() {
bind(event).to(new TypeLiteral<Event<StockEvent>>() {});
}
};
ServiceLocatorUtilities.bind(locator, eventBinder);
}
@Test
public void testIt() {
Service service = locator.getService(Service.class);
assertThat(service.getStock()).isEqualTo("GOOGL UP!");
}
}