测试 Quarkus 应用程序
前言
作为应用程序开发人员,您可以使用红帽构建的 Quarkus 来创建在 OpenShift 和无服务器环境中运行的 Java 编写的基于微服务的应用程序。编译到原生可执行文件的应用程序会占用较少的内存占用空间和快速启动时间。
本指南介绍了如何使用 Apache Maven 以 JVM 模式测试 Quarkus 入门项目以及如何将资源注入测试中。您将展开您在 Quarkus 入门 时创建的测试。
您可以从 Quarkus Quickstart 归档 下载 Quarkus Maven 项目,或克隆 Quarkus Quickstarts Git 存储库。实践位于 get -started-testing 目录中。
先决条件
已安装 OpenJDK (JDK) 11,并且
JAVA_HOME环境变量指定 Java SDK 的位置。- 登录到红帽客户门户网站,从 Software Downloads 页面下载 Red Hat Open JDK 的 Red Hat build。
已安装 Apache Maven 3.8.1 或更高版本。
完成的 Quarkus 入门项目。
- 要了解如何构建 Quarkus 入门项目,请参阅开始使用 Quarkus。
-
或者,您可以下载 Quarkus Quickstart 归档 或克隆
Quarkus QuickstartsGit 存储库。这个示例位于 get-started目录中。
对红帽文档提供反馈
我们非常感谢您对我们的技术内容提供反馈,并鼓励您告诉我们您的想法。如果您想添加评论,提供见解、纠正拼写错误甚至询问问题,您可以在文档中直接这样做。
您必须有一个红帽帐户并登录到客户门户网站。
要从客户门户网站提交文档反馈,请执行以下操作:
- 选择 Multi-page HTML 格式。
- 点文档右上角的 反馈 按钮。
- 突出显示您要提供反馈的文本部分。
- 点高亮文本旁的添加反馈对话框。
- 在页面右侧的文本框中输入您的反馈,然后单击 Submit。
每次提交反馈时,我们都会自动创建跟踪问题。打开在点 Submit 后显示的链接,并开始监视问题或添加更多注释。
感谢您的宝贵反馈。
使开源包含更多
红帽致力于替换我们的代码、文档和 Web 属性中存在问题的语言。我们从这四个术语开始:master、slave、黑名单和白名单。由于此项工作十分艰巨,这些更改将在即将推出的几个发行版本中逐步实施。有关更多详情,请参阅我们的首席技术官 Chris Wright 提供的消息。
第 1 章 验证测试依赖项
在本教程中,您必须有一个已完成的 Quarkus Getting Started 项目,并且项目 pom.xml 文件必须包含 quarkus-junit5 和 rest-assured 依赖项。如果您完成了 Quarkus 入门操作,或者下载了完成的示例,则会出现这些依赖项。
-
测试需要
quarkus-junit5依赖项,因为它提供了控制测试框架的@QuarkusTest注解。 不需要
rest-assured依赖项,但您可以将其用作测试 HTTP 端点的便捷方式。注意Quarkus 提供自动设置正确 URL 的集成,因此不需要配置。
流程
-
打开 Getting Started 项目
pom.xml文件。 验证以下依赖项是否在文件中,并根据需要添加它们:
<dependency> <groupId>io.quarkus</groupId> <artifactId>quarkus-junit5</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>io.rest-assured</groupId> <artifactId>rest-assured</artifactId> <scope>test</scope> </dependency>验证您的
pom.xml文件是否包含maven-surefire-plugin。由于本教程使用 JUnit 5 框架,所以必须设置maven-surefire-plugin的版本,因为默认版本不支持 Junit 5:<plugin> <artifactId>maven-surefire-plugin</artifactId> <version>${surefire-plugin.version}</version> <configuration> <systemProperties> <java.util.logging.manager>org.jboss.logmanager.LogManager</java.util.logging.manager> </systemProperties> </configuration> </plugin>-
设置
java.util.logging.manager系统属性,以使用正确的日志管理器进行测试。 验证
GreetingResourceTest.java文件是否包含以下内容,并根据需要添加该文件:package org.acme.quickstart; import io.quarkus.test.junit.QuarkusTest; import org.junit.jupiter.api.Test; import java.util.UUID; import static io.restassured.RestAssured.given; import static org.hamcrest.CoreMatchers.is; @QuarkusTest public class GreetingResourceTest { @Test public void testHelloEndpoint() { given() .when().get("/hello") .then() .statusCode(200) .body(is("hello")); } @Test public void testGreetingEndpoint() { String uuid = UUID.randomUUID().toString(); given() .pathParam("name", uuid) .when().get("/hello/greeting/{name}") .then() .statusCode(200) .body(is("hello " + uuid)); } }要运行测试,请输入以下命令:
./mvnw clean verify
您还可以直接从 IDE 运行测试。
此测试使用 HTTP 来直接测试 REST 端点。触发测试后,应用程序将在测试运行前启动。
第 2 章 指定测试端口
默认情况下,Quarkus 测试在端口 8081 上运行,以避免与正在运行的应用程序冲突。这可让您在应用程序并行运行时运行测试。您可以在 application.properties 文件中指定不同的端口来测试连接。您可以使用单独的端口来测试不受保护的 HTTP 连接,以及使用 SSL 保护的连接。
流程
在
application.properties文件中设置quarkus.http.test-port和quarkus.http.test-ssl-port属性。将<port> 替换为您要用于测试连接的端口号:quarkus.http.test-port=<port> quarkus.http.test-ssl-port=<port>
您可以将端口号设置为
0,以便您的操作系统从系统中的可用端口范围内分配一个随机端口。注意Quarkus 提供 REST the 集成,在测试运行前更新 REST 导航器使用的默认端口,因此不需要额外的配置。
第 3 章 为 HTTP 测试连接设置响应时间
当您使用 REST Swarm 测试应用程序中 REST API 时,默认连接和响应时间周期被设置为 30 秒。您可以更改应用程序的超时时间长度。
流程
-
打开应用程序项目中的
application.properties文件: 将
quarkus.http.test-timeout属性的值设置为您要为超时时间设置的持续时间长度,后跟您要在其中设置持续时间的单位:application.properties
quarkus.http.test-timeout=<duration>
例如,将响应超时时间的持续时间设置为 10 秒:
application.properties
quarkus.http.test-timeout=10s
第 4 章 将 URL 注入测试
如果要使用其他客户端,请使用 Quarkus @TestHTTPResource 注释直接将要测试的应用 URL 注入测试类的字段中。此字段可以是 字符串、URL 或 URI 类型。您还可以在此注解中提供测试路径。在这一实践中,您将编写一个加载静态资源的简单测试。
流程
使用以下内容创建
src/main/resources/META-INF/resources/index.html文件:<html> <head> <title>Testing Guide</title> </head> <body> Information about testing </body> </html>使用以下内容创建
StaticContentTest.java文件来测试index.html是否被正确提供:package org.acme.quickstart; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.net.URL; import java.nio.charset.StandardCharsets; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import io.quarkus.test.common.http.TestHTTPResource; import io.quarkus.test.junit.QuarkusTest; @QuarkusTest public class StaticContentTest { @TestHTTPResource("index.html") 1 URL url; @Test public void testIndexHtml() throws Exception { try (InputStream in = url.openStream()) { String contents = readStream(in); Assertions.assertTrue(contents.contains("<title>Testing Guide</title>")); } } private static String readStream(InputStream in) throws IOException { byte[] data = new byte[1024]; int r; ByteArrayOutputStream out = new ByteArrayOutputStream(); while ((r = in.read(data)) > 0) { out.write(data, 0, r); } return new String(out.toByteArray(), StandardCharsets.UTF_8); } }- 1
@TestHTTPResource注释允许您直接注入 Quarkus 实例的 URL。注解的值是 URL 的路径组件。
第 5 章 将 CDI Bean 注入测试
您可以直接执行单元测试并测试 CDI Bean。Quarkus 可让您通过 @Inject 注释将 CDI Bean 注入测试中。实际上,Quarkus 中的测试是完整的 CDI Bean,因此您可以使用完整的 CDI 功能。
无法在原生测试中使用注入。
流程
使用以下内容创建
GreetingServiceTest.java文件:package org.acme.quickstart; import javax.inject.Inject; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import io.quarkus.test.junit.QuarkusTest; @QuarkusTest public class GreetingServiceTest { @Inject 1 GreetingService service; @Test public void testGreetingService() { Assertions.assertEquals("hello Quarkus", service.greeting("Quarkus")); } }- 1
GreetingServicebean 将注入到测试中。
第 6 章 将拦截器应用到测试
Quarkus 测试是完整的 CDI Bean,因此您可以像通常一样应用 CDI 拦截器。例如,如果您希望测试方法在事务的上下文中运行,您可以将 @Transactional 注释应用到该方法。您还可以创建自己的测试 stereotypes。
流程
将
quarkus-narayana-jta依赖项添加到pom.xml文件中:<dependency> <groupId>io.quarkus</groupId> <artifactId>quarkus-narayana-jta</artifactId> </dependency>确保
TransactionalQuarkusTest.java包括以下导入语句:package org.acme.quickstart; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import javax.enterprise.inject.Stereotype; import javax.transaction.Transactional; import io.quarkus.test.junit.QuarkusTest;
创建
@TransactionalQuarkusTest注释:@QuarkusTest @Stereotype @Transactional @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) public @interface TransactionalQuarkusTest { }将此注解应用到一个测试类,它的行为如同您应用了
@QuarkusTest和@Transactional注解一样:@TransactionalQuarkusTest public class TestStereotypeTestCase { @Inject UserTransaction userTransaction; @Test public void testUserTransaction() throws Exception { Assertions.assertEquals(Status.STATUS_ACTIVE, userTransaction.getStatus()); } }这是一个简单的测试,在不使用 HTTP 的情况下直接评估问候服务。
第 7 章 模拟 CDI Bean
Quarkus 允许您模拟特定测试的特定 CDI Bean。
您可以使用以下方法之一模拟对象:
-
使用
src/test/java目录中的类覆盖您要模拟的 bean,并将@Alternative和@Priority (1)注解放在 bean 中。 -
使用
io.quarkus.test.Mockstereotype 注解。@Mock注释包含@Alternative、@Priority (1)和@Dependent注释。
以下步骤演示了如何使用 @Alternative 注释模拟外部服务。请注意,此方法不适用于原生镜像测试,因为原生镜像不包含测试替代方案。
流程
在
src/main/java目录中创建ExternalService,类似以下示例:package org.acme.quickstart; import javax.enterprise.context.ApplicationScoped; @ApplicationScoped public class ExternalService { public String service() { return "external"; } }在
src/main/java目录中创建一个使用ExternalService的类UsesExternalService:package org.acme.quickstart; import javax.enterprise.context.ApplicationScoped; import javax.inject.Inject; @ApplicationScoped public class UsesExternalService { @Inject ExternalService externalService; public String doSomething() { return externalService.service(); } }在
src/test/java目录中创建一个测试,类似以下示例:package org.acme.quickstart; import javax.inject.Inject; import io.quarkus.test.junit.QuarkusTest; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; @QuarkusTest class UsesExternalServiceTest { @Inject UsesExternalService usesExternalService; @Test public void testDoSomething() { Assertions.assertEquals("external", usesExternalService.doSomething()); } }在
src/test/java中创建使用@Alternative注解的MockExternalService:package org.acme.quickstart; import javax.annotation.Priority; import javax.enterprise.context.ApplicationScoped; import javax.enterprise.inject.Alternative; @Alternative @Priority(1) @ApplicationScoped public class MockExternalService extends ExternalService { 1 @Override public String service() { return "mock"; } }- 1
MockExternalService在什么地方注入使用ExternalService。在本例中,MockExternalService将在UsesExternalService中使用。
注意您可以使用
@Mock注释,而不是@Alternative、@Priority (1)和@Dependent注释。以下示例演示了如何创建使用
@Mock注解的MockExternalService类:import javax.enterprise.context.ApplicationScoped; import io.quarkus.test.Mock; @Mock @ApplicationScoped public class MockExternalService extends ExternalService { @Override public String service() { return "mock"; } }在测试中将 asserted 字符串从
"external"改为"mock":package org.acme.quickstart; import javax.inject.Inject; import io.quarkus.test.junit.QuarkusTest; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; @QuarkusTest class UsesExternalServiceTest { @Inject UsesExternalService usesExternalService; @Test public void testDoSomething() { Assertions.assertEquals("mock", usesExternalService.doSomething()); } }
第 8 章 其他资源
更新于 2023-05-16