测试 Quarkus 应用程序

Red Hat build of Quarkus 1.11

摘要

本指南论述了如何测试 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 入门项目。

对红帽文档提供反馈

我们非常感谢您对我们的技术内容提供反馈,并鼓励您告诉我们您的想法。如果您想添加评论,提供见解、纠正拼写错误甚至询问问题,您可以在文档中直接这样做。

注意

您必须有一个红帽帐户并登录到客户门户网站。

要从客户门户网站提交文档反馈,请执行以下操作:

  1. 选择 Multi-page HTML 格式。
  2. 点文档右上角的 反馈 按钮。
  3. 突出显示您要提供反馈的文本部分。
  4. 点高亮文本旁的添加反馈对话框。
  5. 在页面右侧的文本框中输入您的反馈,然后单击 Submit

每次提交反馈时,我们都会自动创建跟踪问题。打开在点 Submit 后显示的链接,并开始监视问题或添加更多注释。

感谢您的宝贵反馈。

使开源包含更多

红帽致力于替换我们的代码、文档和 Web 属性中存在问题的语言。我们从这四个术语开始:master、slave、黑名单和白名单。由于此项工作十分艰巨,这些更改将在即将推出的几个发行版本中逐步实施。有关更多详情,请参阅我们的首席技术官 Chris Wright 提供的消息

第 1 章 验证测试依赖项

在本教程中,您必须有一个已完成的 Quarkus Getting Started 项目,并且项目 pom.xml 文件必须包含 quarkus-junit5rest-assured 依赖项。如果您完成了 Quarkus 入门操作,或者下载了完成的示例,则会出现这些依赖项。

  • 测试需要 quarkus-junit5 依赖项,因为它提供了控制测试框架的 @QuarkusTest 注解。
  • 不需要 rest-assured 依赖项,但您可以将其用作测试 HTTP 端点的便捷方式。

    注意

    Quarkus 提供自动设置正确 URL 的集成,因此不需要配置。

流程

  1. 打开 Getting Started 项目 pom.xml 文件。
  2. 验证以下依赖项是否在文件中,并根据需要添加它们:

    <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>
  3. 验证您的 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>
  4. 设置 java.util.logging.manager 系统属性,以使用正确的日志管理器进行测试。
  5. 验证 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));
        }
    
    }
  6. 要运行测试,请输入以下命令:

    ./mvnw clean verify

    您还可以直接从 IDE 运行测试。

注意

此测试使用 HTTP 来直接测试 REST 端点。触发测试后,应用程序将在测试运行前启动。

第 2 章 指定测试端口

默认情况下,Quarkus 测试在端口 8081 上运行,以避免与正在运行的应用程序冲突。这可让您在应用程序并行运行时运行测试。您可以在 application.properties 文件中指定不同的端口来测试连接。您可以使用单独的端口来测试不受保护的 HTTP 连接,以及使用 SSL 保护的连接。

流程

  • application.properties 文件中设置 quarkus.http.test-portquarkus.http.test-ssl-port 属性。将 & lt;port> 替换为您要用于测试连接的端口号:

    quarkus.http.test-port=<port>
    quarkus.http.test-ssl-port=<port>

    您可以将端口号设置为 0, 以便您的操作系统从系统中的可用端口范围内分配一个随机端口。

    注意

    Quarkus 提供 REST the 集成,在测试运行前更新 REST 导航器使用的默认端口,因此不需要额外的配置。

第 3 章 为 HTTP 测试连接设置响应时间

当您使用 REST Swarm 测试应用程序中 REST API 时,默认连接和响应时间周期被设置为 30 秒。您可以更改应用程序的超时时间长度。

流程

  1. 打开应用程序项目中的 application.properties 文件:
  2. quarkus.http.test-timeout 属性的值设置为您要为超时时间设置的持续时间长度,后跟您要在其中设置持续时间的单位:

    application.properties

    quarkus.http.test-timeout=<duration>

    例如,将响应超时时间的持续时间设置为 10 秒:

    application.properties

    quarkus.http.test-timeout=10s

第 4 章 将 URL 注入测试

如果要使用其他客户端,请使用 Quarkus @TestHTTPResource 注释直接将要测试的应用 URL 注入测试类的字段中。此字段可以是 字符串URLURI 类型。您还可以在此注解中提供测试路径。在这一实践中,您将编写一个加载静态资源的简单测试。

流程

  1. 使用以下内容创建 src/main/resources/META-INF/resources/index.html 文件:

    <html>
        <head>
            <title>Testing Guide</title>
        </head>
        <body>
            Information about testing
        </body>
    </html>
  2. 使用以下内容创建 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
    GreetingService bean 将注入到测试中。

第 6 章 将拦截器应用到测试

Quarkus 测试是完整的 CDI Bean,因此您可以像通常一样应用 CDI 拦截器。例如,如果您希望测试方法在事务的上下文中运行,您可以将 @Transactional 注释应用到该方法。您还可以创建自己的测试 stereotypes。

流程

  1. quarkus-narayana-jta 依赖项添加到 pom.xml 文件中:

    <dependency>
        <groupId>io.quarkus</groupId>
        <artifactId>quarkus-narayana-jta</artifactId>
    </dependency>
  2. 确保 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;
  3. 创建 @TransactionalQuarkusTest 注释:

    @QuarkusTest
    @Stereotype
    @Transactional
    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.TYPE)
    public @interface TransactionalQuarkusTest {
    }
  4. 将此注解应用到一个测试类,它的行为如同您应用了 @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.Mock stereotype 注解。@Mock 注释包含 @Alternative@Priority (1)@Dependent 注释。

以下步骤演示了如何使用 @Alternative 注释模拟外部服务。请注意,此方法不适用于原生镜像测试,因为原生镜像不包含测试替代方案。

流程

  1. src/main/java 目录中创建 ExternalService,类似以下示例:

    package org.acme.quickstart;
    
    import javax.enterprise.context.ApplicationScoped;
    
    @ApplicationScoped
    public class ExternalService {
    
        public String service() {
            return "external";
        }
    
    }
  2. 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();
        }
    }
  3. 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());
        }
    }
  4. 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";
        }
    }
  5. 在测试中将 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

法律通告

Copyright © 2023 Red Hat, Inc.
The text of and illustrations in this document are licensed by Red Hat under a Creative Commons Attribution–Share Alike 3.0 Unported license ("CC-BY-SA"). An explanation of CC-BY-SA is available at http://creativecommons.org/licenses/by-sa/3.0/. In accordance with CC-BY-SA, if you distribute this document or an adaptation of it, you must provide the URL for the original version.
Red Hat, as the licensor of this document, waives the right to enforce, and agrees not to assert, Section 4d of CC-BY-SA to the fullest extent permitted by applicable law.
Red Hat, Red Hat Enterprise Linux, the Shadowman logo, the Red Hat logo, JBoss, OpenShift, Fedora, the Infinity logo, and RHCE are trademarks of Red Hat, Inc., registered in the United States and other countries.
Linux® is the registered trademark of Linus Torvalds in the United States and other countries.
Java® is a registered trademark of Oracle and/or its affiliates.
XFS® is a trademark of Silicon Graphics International Corp. or its subsidiaries in the United States and/or other countries.
MySQL® is a registered trademark of MySQL AB in the United States, the European Union and other countries.
Node.js® is an official trademark of Joyent. Red Hat is not formally related to or endorsed by the official Joyent Node.js open source or commercial project.
The OpenStack® Word Mark and OpenStack logo are either registered trademarks/service marks or trademarks/service marks of the OpenStack Foundation, in the United States and other countries and are used with the OpenStack Foundation's permission. We are not affiliated with, endorsed or sponsored by the OpenStack Foundation, or the OpenStack community.
All other trademarks are the property of their respective owners.