使用 Quarkus 进行依赖注入
Dependency Injection with Quarkus
我是 Quarkus 的新手,我正在尝试为一个名为 DummyReceiver
的对象编写测试。我知道 Quarkus 提供 @Mock
和其他创建模拟对象的方法,但这有一个缺点,即所有测试中的 every 实例将被替换为相同的模拟,我不想那。所以我尝试做一个简单的依赖注入。
以下是最重要的配置:
<properties>
<compiler-plugin.version>3.8.1</compiler-plugin.version>
<maven.compiler.parameters>true</maven.compiler.parameters>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<quarkus-plugin.version>1.13.3.Final</quarkus-plugin.version>
<quarkus.platform.artifact-id>quarkus-universe-bom</quarkus.platform.artifact-id>
<quarkus.platform.group-id>io.quarkus</quarkus.platform.group-id>
<quarkus.platform.version>1.13.3.Final</quarkus.platform.version>
<wiremock.version>2.28.0</wiremock.version>
<spotless.version>2.11.0</spotless.version>
<surefire-plugin.version>3.0.0-M5</surefire-plugin.version>
</properties>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-junit5</artifactId>
<scope>test</scope>
</dependency>
我的代码是这样的:
public interface DummyDependencyInterface {
void store(String id);
}
import javax.enterprise.context.ApplicationScoped;
@ApplicationScoped
public class DummyDependency implements DummyDependencyInterface {
public void store(String id) {
System.out.println("DummyDependency stored: " + id);
}
}
public class DummyMessage {
private final String scannerInput;
public DummyMessage(String scannerInput) {
this.scannerInput = scannerInput;
}
public String getScannerInput() {
return this.scannerInput;
}
}
import ch.scs.mbv.vega.websocket.ScannerSocketMessage;
import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.event.Observes;
@ApplicationScoped
public class DummyReceiver {
private DummyDependencyInterface dependency;
public DummyReceiver(DummyDependencyInterface dependency) {
System.out.println("DummyReceiver created with " + dependency.getClass().getName());
this.dependency = dependency;
}
public void onProcessScannerMessage(@Observes DummyMessage message) {
String scan = message.getScannerInput();
dependency.store(scan);
}
}
然后我像这样进行测试:
import java.util.concurrent.LinkedBlockingDeque;
public class DummyDependencyMock implements DummyDependencyInterface {
public LinkedBlockingDeque<String> ids = new LinkedBlockingDeque<>();
public void store(String id) {
ids.add(id);
System.out.println("DummyDependencyMock stored: " + id);
}
}
import io.quarkus.test.junit.QuarkusTest;
import java.util.concurrent.TimeUnit;
import javax.enterprise.event.Event;
import javax.inject.Inject;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@QuarkusTest
public class DummyReceiverTest {
@Inject
Event<DummyMessage> messageEvent;
private DummyDependencyMock mock;
private DummyReceiver receiver;
@BeforeEach
public void setup() {
mock = new DummyDependencyMock();
receiver = new DummyReceiver(mock);
}
@Test
public void test() throws Exception {
String id = "123";
messageEvent.fire(new DummyMessage(id));
String storedId = mock.ids.poll(1, TimeUnit.SECONDS);
Assertions.assertEquals("123", storedId);
}
}
输出显示
DummyReceiver created with scanning.DummyDependencyMock
DummyReceiver created with scanning.DummyDependency_ClientProxy
DummyDependency stored: 123
org.opentest4j.AssertionFailedError:
Expected :123
Actual :null
有谁知道出了什么问题以及如何解决?有更好的方法吗?任何建议表示赞赏!
更新:解决方案示例
以下示例用于说明目的,展示了我能想到的最简单的可能解决方案。 Example
就是我们要测试的class:
import javax.enterprise.context.ApplicationScoped;
@ApplicationScoped
public class Example {
private Delegate delegate;
Example(Delegate delegate) {
this.delegate = delegate;
}
public void doIt() {
delegate.execute();
}
}
我们想要模拟的依赖称为 Delegate
:
import javax.enterprise.context.ApplicationScoped;
@ApplicationScoped
public class Delegate {
public void execute() {
}
}
我们可以编写以下测试来验证 Example
调用了 Delegate
的方法 execute
:
import static org.mockito.Mockito.verify;
import io.quarkus.test.junit.QuarkusTest;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.MockitoAnnotations;
import org.mockito.junit.jupiter.MockitoExtension;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
@QuarkusTest
@ExtendWith(MockitoExtension.class)
public class ExampleTest {
@Mock
Delegate delegateMock;
@InjectMocks
Example example;
@BeforeEach
public void setup() {
MockitoAnnotations.openMocks(this);
}
@Test
public void test() {
example.doIt();
verify(delegateMock).execute();
}
}
您在测试中创建的 DummyReceiver
无论如何都不为应用程序的其余部分所知。
如果您想模拟 DummyDependencyMock
,在 Quarkus 中有多种方法可以实现,但 @io.quarkus.test.junit.mockito.InjectMock
是迄今为止最简单的方法。
你的代码看起来像
@QuarkusTest
public class DummyReceiverTest {
@Inject
Event<DummyMessage> messageEvent;
@InjectMock
private DummyDependencyMock mock;
@Test
public void test() throws Exception {
String id = "123";
messageEvent.fire(new DummyMessage(id));
String storedId = mock.ids.poll(1, TimeUnit.SECONDS);
Assertions.assertEquals("123", storedId);
}
}
请注意,使用 @InjectMock
仅更改特定测试的模拟 - 有关更多详细信息,请参阅 this
geoand 几乎答对了,他的回答帮我解决了剩下的问题 - 谢谢!!!这是对我有用的代码:
import io.quarkus.test.junit.QuarkusTest;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.MockitoAnnotations;
import org.mockito.junit.jupiter.MockitoExtension;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
@QuarkusTest
@ExtendWith(MockitoExtension.class)
public class DummyReceiverTest {
@Inject
Event<DummyMessage> messageEvent;
@InjectMock
private DummyDependencyMock mock;
@BeforeEach
public void setup() {
MockitoAnnotations.openMocks(this);
}
@Test
public void test() throws Exception {
String id = "123";
messageEvent.fire(new DummyMessage(id));
String storedId = mock.ids.poll(1, TimeUnit.SECONDS);
Assertions.assertEquals("123", storedId);
}
}
我是 Quarkus 的新手,我正在尝试为一个名为 DummyReceiver
的对象编写测试。我知道 Quarkus 提供 @Mock
和其他创建模拟对象的方法,但这有一个缺点,即所有测试中的 every 实例将被替换为相同的模拟,我不想那。所以我尝试做一个简单的依赖注入。
以下是最重要的配置:
<properties>
<compiler-plugin.version>3.8.1</compiler-plugin.version>
<maven.compiler.parameters>true</maven.compiler.parameters>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<quarkus-plugin.version>1.13.3.Final</quarkus-plugin.version>
<quarkus.platform.artifact-id>quarkus-universe-bom</quarkus.platform.artifact-id>
<quarkus.platform.group-id>io.quarkus</quarkus.platform.group-id>
<quarkus.platform.version>1.13.3.Final</quarkus.platform.version>
<wiremock.version>2.28.0</wiremock.version>
<spotless.version>2.11.0</spotless.version>
<surefire-plugin.version>3.0.0-M5</surefire-plugin.version>
</properties>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-junit5</artifactId>
<scope>test</scope>
</dependency>
我的代码是这样的:
public interface DummyDependencyInterface {
void store(String id);
}
import javax.enterprise.context.ApplicationScoped;
@ApplicationScoped
public class DummyDependency implements DummyDependencyInterface {
public void store(String id) {
System.out.println("DummyDependency stored: " + id);
}
}
public class DummyMessage {
private final String scannerInput;
public DummyMessage(String scannerInput) {
this.scannerInput = scannerInput;
}
public String getScannerInput() {
return this.scannerInput;
}
}
import ch.scs.mbv.vega.websocket.ScannerSocketMessage;
import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.event.Observes;
@ApplicationScoped
public class DummyReceiver {
private DummyDependencyInterface dependency;
public DummyReceiver(DummyDependencyInterface dependency) {
System.out.println("DummyReceiver created with " + dependency.getClass().getName());
this.dependency = dependency;
}
public void onProcessScannerMessage(@Observes DummyMessage message) {
String scan = message.getScannerInput();
dependency.store(scan);
}
}
然后我像这样进行测试:
import java.util.concurrent.LinkedBlockingDeque;
public class DummyDependencyMock implements DummyDependencyInterface {
public LinkedBlockingDeque<String> ids = new LinkedBlockingDeque<>();
public void store(String id) {
ids.add(id);
System.out.println("DummyDependencyMock stored: " + id);
}
}
import io.quarkus.test.junit.QuarkusTest;
import java.util.concurrent.TimeUnit;
import javax.enterprise.event.Event;
import javax.inject.Inject;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@QuarkusTest
public class DummyReceiverTest {
@Inject
Event<DummyMessage> messageEvent;
private DummyDependencyMock mock;
private DummyReceiver receiver;
@BeforeEach
public void setup() {
mock = new DummyDependencyMock();
receiver = new DummyReceiver(mock);
}
@Test
public void test() throws Exception {
String id = "123";
messageEvent.fire(new DummyMessage(id));
String storedId = mock.ids.poll(1, TimeUnit.SECONDS);
Assertions.assertEquals("123", storedId);
}
}
输出显示
DummyReceiver created with scanning.DummyDependencyMock
DummyReceiver created with scanning.DummyDependency_ClientProxy
DummyDependency stored: 123
org.opentest4j.AssertionFailedError:
Expected :123
Actual :null
有谁知道出了什么问题以及如何解决?有更好的方法吗?任何建议表示赞赏!
更新:解决方案示例
以下示例用于说明目的,展示了我能想到的最简单的可能解决方案。 Example
就是我们要测试的class:
import javax.enterprise.context.ApplicationScoped;
@ApplicationScoped
public class Example {
private Delegate delegate;
Example(Delegate delegate) {
this.delegate = delegate;
}
public void doIt() {
delegate.execute();
}
}
我们想要模拟的依赖称为 Delegate
:
import javax.enterprise.context.ApplicationScoped;
@ApplicationScoped
public class Delegate {
public void execute() {
}
}
我们可以编写以下测试来验证 Example
调用了 Delegate
的方法 execute
:
import static org.mockito.Mockito.verify;
import io.quarkus.test.junit.QuarkusTest;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.MockitoAnnotations;
import org.mockito.junit.jupiter.MockitoExtension;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
@QuarkusTest
@ExtendWith(MockitoExtension.class)
public class ExampleTest {
@Mock
Delegate delegateMock;
@InjectMocks
Example example;
@BeforeEach
public void setup() {
MockitoAnnotations.openMocks(this);
}
@Test
public void test() {
example.doIt();
verify(delegateMock).execute();
}
}
您在测试中创建的 DummyReceiver
无论如何都不为应用程序的其余部分所知。
如果您想模拟 DummyDependencyMock
,在 Quarkus 中有多种方法可以实现,但 @io.quarkus.test.junit.mockito.InjectMock
是迄今为止最简单的方法。
你的代码看起来像
@QuarkusTest
public class DummyReceiverTest {
@Inject
Event<DummyMessage> messageEvent;
@InjectMock
private DummyDependencyMock mock;
@Test
public void test() throws Exception {
String id = "123";
messageEvent.fire(new DummyMessage(id));
String storedId = mock.ids.poll(1, TimeUnit.SECONDS);
Assertions.assertEquals("123", storedId);
}
}
请注意,使用 @InjectMock
仅更改特定测试的模拟 - 有关更多详细信息,请参阅 this
geoand 几乎答对了,他的回答帮我解决了剩下的问题 - 谢谢!!!这是对我有用的代码:
import io.quarkus.test.junit.QuarkusTest;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.MockitoAnnotations;
import org.mockito.junit.jupiter.MockitoExtension;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
@QuarkusTest
@ExtendWith(MockitoExtension.class)
public class DummyReceiverTest {
@Inject
Event<DummyMessage> messageEvent;
@InjectMock
private DummyDependencyMock mock;
@BeforeEach
public void setup() {
MockitoAnnotations.openMocks(this);
}
@Test
public void test() throws Exception {
String id = "123";
messageEvent.fire(new DummyMessage(id));
String storedId = mock.ids.poll(1, TimeUnit.SECONDS);
Assertions.assertEquals("123", storedId);
}
}