1.概述

Quarkus使这些天很容易开发强大和清洁的应用程序。但怎么样测试?金宝搏官网188be

在本教程中,我们将仔细查看Quarkus应用程序如何测试.我们将探索Quarkus和Quarkus提供的测试可能性提供了一些概念,如依赖管理和注入、mock、配置文件配置,以及更具体的东西,如Quarkus注释和本地可执行文件测试

2.设置

让我们从之前配置的基本Quarkus项目开始千万乌克西奥指南

首先,我们将添加Quarkus-Reasteasy-JacksonQuarkus-Hibernate-Orm-PancuteQuarkus-JDBC-H2quarkus-junit5-mockito, 和quarkus-test-h2Maven的依赖关系:

<依赖>  io.quarkus   Quarkus-Resteasy-Jackson   <依赖项>  IO.Quarkus   Quarkus-Hibernate-Orm-Panache   <依赖项>  IO.quarkus   Quarkus-JDBC-H2   <依赖项>  io.quarkus   Quarkus-Junit5-Mockito   <依赖项>  IO.Quarkus   Quarkus-Test-H2  

接下来,让我们创建我们的域实体:

公共类书扩展了PanCheententity {私有字符串标题;私人弦作者;}

我们继续添加一个简单的Panache存储库,使用方法来搜索书籍:

公共类书籍提供Panacherepository {公共流 findby(String查询){return查找(“作者喜欢:查询或标题:查询”,with(“查询”,“%”+查询+“%”))。流();}}

现在,让我们写一个LibraryService持有任何业务逻辑:

公共类Libraryservice {public set  find(string查询){if(查询== null){return bookRepository.findall()。Stream()。收集(Toset());返回bookrepository.findby(查询).collect(toset());}}

最后,让我们通过创建一个HTTP来通过HTTP公开我们的服务功能libraryResource.

@path(“/ library”)公共类LibraryResource {@get @path(“/ book”)公共设置查找手册(@queryparam(“查询”)字符串查询){return libraryservice.find(查询);}}

3。@Alternative实现

在编写任何测试之前,让我们确保我们的存储库中有一些书籍。与夸克,我们可以使用CDI@Alternative为我们的测试提供自定义Bean实现的机制.让我们创造一个testbookrepository.延伸BookRepository.

@priority(1)@Alternpiation @ApplicationScoped公共类TestBookRepository扩展了BookRepository {@PostConstruct Public Void Init(){持久性(“新书(”弗兰·赫伯特“),新书(”基金会“,”Isaac Asimov“));}}

我们将这个替代豆子放在我们的测试包装,而因@priority(1)@Alternative注解,我们确信任何测试都会选择它BookRepository.实现。这是一种方式,我们可以提供所有夸克测试的全球模拟可以使用。我们将不久探讨更加窄的模拟,但现在,让我们继续前进到创建我们的第一次测试。

4. HTTP集成测试

让我们从创建一个简单的REST-assured集成测试开始:

@quarkustest类libraryresourceintegrationtest {@test void whongetbooksbytitle_thenbookshouldbefound(){给定()。contentType(contentType.json).param(“查询”,“dune”).when()。get(“/ library / book”).then().statuscode(200).body(“size()”,是(1)).body(“title”,hasitem(“dune”)).Body(“作者”,Hasitem(“Frank Herbert”));}}

测试,注释@quarkustest,首先启动Quarkus应用程序然后对资源的端点执行一系列HTTP请求。

现在,让我们利用一些夸克机制来试图进一步改善我们的测试。

4.1。URL注入@TestHTTPResource

而不是硬编码我们的HTTP端点的路径,让我们注入资源URL:

@TestHTTPResource(“/图书馆/书”)URL libraryEndpoint;

然后,让我们在我们的请求中使用它:

给定()。param(“查询”,“dune”).when()。get(图书馆诚信号).then()。statuscode(200);

或者,在不使用休息的情况下,让我们只需打开与注入的URL的连接并测试响应:

@Test void当getbooks_thenbooksshouldbefound()抛出IOException {assertTrue(IOUtils.toString(libraryEndpoint.openStream(), defaultCharset()).contains("Asimov"));}

我们可以看到,@TestHTTPResourceURL注入为我们提供了一种简单而灵活的访问我们的端点。

4.2。@testhttpendpoint.

让我们进一步使用提供的Quarkus配置我们的端点@testhttpendpoint.注解:

@testhttpendpoint(libraryResource.class)@testhttpreSource(“Book”)URL LibraryEndPoint;

这样,如果我们决定改变的路径libraryResource.,测试将拿起正确的路径,没有我们必须触摸它。

@testhttpendpoint.也可以应用于课程级别,在这种情况下,休息会自动前缀所有请求小路libraryResource.

@QuarkusTest @TestHTTPEndpoint(LibraryResource.class) class LibraryHttpEndpointIntegrationTest {@Test void whenGetBooks_thenShouldReturnSuccessfully() {given().contentType(ContentType.JSON) .when().get("book") .then().statusCode(200);}}

5.上下文和依赖注入

当谈到依赖注入时,在Quarkus测试中,我们可以使用@注入对于任何所需的依赖性.让我们通过为我们的测试来看看这一点LibraryService

@QuarkusTest类LibraryServiceIntegrationTest{@注入LibraryService LibraryService;@Test void whenFindByAuthor_thenBookShouldBeFound() {assertFalse(libraryService。找到(Frank Herbert) .isEmpty ());}}

现在,让我们试着测试一下我们的PanacheBookRepository.

class BookRepositoryIntegrationTest {@Inject BookRepository BookRepository;@Test void givenbookrepository_whenfindbyauthor_thenshouldreturnbookfromrepository () {assertTrue(bookRepository.findBy(“Herbert”).findAny().isPresent());}}

但当我们运行测试时,它失败了。那是因为它需要在交易的上下文中运行并且没有活动。这可以简单地通过添加来解决@ transactional到测试类。或者,如果我们愿意,我们可以定义自己的刻板印象来捆绑两者@quarkustest.@transactional。让我们通过创建@QuarkusTransactionalTest注解:

@quarkustest @stereotype @transactional @target(emplementtype.type)@retention(RetentionPolicy.Runtime)公共@Interface QuarkustraneActionalTIALYTEST {}

现在,让我们将它应用于我们的测试:

@quarkustransactionaltialstast ashoubrepositoryIntegrationtest.

我们可以看到,因为Quarkus测试是完整的CDI bean,我们可以利用依赖注入,交易环境和CDI拦截器等所有CDI益处。

6.嘲笑

mock是任何测试工作的关键方面。正如我们在上面已经看到的,Quarkus测试可以利用CDI@Alternative机制。我们现在深入进入夸克提供的嘲弄能力。

6.1。@嘲笑

作为轻微简化了@Alternative方法,我们可以使用@嘲笑构造型注解。这捆绑在一起@Alternative@primary(1)注释。

6.2。@QuarkusMock

如果我们不想有一个全局定义的mock,但更愿意只有我们的模拟只在一个测试范围内,我们可以使用@QuarkusMock

@QuarkusTest类LibraryServiceQuarkusMockUnitTest {@Inject LibraryService;@BeforeEach void setUp() {BookRepository mock = Mockito.mock(TestBookRepository.class);Mockito.when (mock.findBy(“阿西莫夫”)).thenReturn(数组。new Book[] {new Book(“Foundation”,“Isaac Asimov”),new Book(“I Robot”,“Isaac Asimov”)});QuarkusMock。installMockForType(模拟、BookRepository.class);} @Test void whenFindByAuthor_thenBooksShouldBeFound() {assertEquals(2, libraryService.find("Asimov").size());}}

6.3。@injectmock.

让我们简化一下和使用Quarkus.@injectmock.注释,而不是@QuarkusMock

@quarkustest类libraryserviceinjectmockunittest {@inject libraryservice libraryservice;@InjectMock BookRepository BookRepository;@beforeeach void setup(){何时(bookrepository.findby(“frank herbert”)).thenreturn(arrays.stream(新书[] {新书(“dune”,“frank herbert”),新书(“孩子们沙丘“,”弗兰克赫伯特“)}));@test void时void whenfindbyauthor_thenbooksshouldbefound(){assertequals(2,libraryservice.find(“frank herbert”)。大小());}}

6.4。@injectspy.

如果我们只对监视感兴趣,而不是取代bean的行为,我们可以使用所提供的@injectspy.注解:

@quarkustest类libraryresourceinjectspyintegrationtest {@injectspy libraryservice libraryservice;@test void whongetbooksbyauthor_thenbookshouldbefound(){给定()。contentType(contentType.json).param(“查询”,“asimov”).when()。get()。get()。statecode statuscode(200);验证(Libraryservice).find(“Asimov”);}}

7.测试档案

我们可能想要以不同的配置运行我们的测试.为此,Quarkus提供了测试配置文件的概念.让我们创建一个测试,它使用我们的自定义版本对不同的数据库引擎运行BookRepository.,并且还将在已配置的路径中公开我们的HTTP资源。

为此,我们首先实现一个QuarkusTestProfile

public class CustomTestProfile implements QuarkusTestProfile {@Override public Map getConfigOverrides() {return Collections.singletonMap("quarkus.resteasy. getConfigOverrides() ";路径”、“/自定义”);} @Override public Set> getEnabledAlternatives() {return Collections.singleton(TestBookRepository.class);} @Override public String getConfigProfile(){返回“定制配置文件”;}}

让我们现在配置我们的application.properties.通过添加一个自定义档案配置属性将从内存更改为文件的H2存储:

% custom-profile.quarkus.datasource.jdbc。url = jdbc: h2: testdb文件:。/

最后,在所有资源和配置就绪后,让我们编写我们的测试:

@quarkustest @testprofile(custombookrepositoryprofile.class)class customlibraryresourcemanualtest {public static final string bookstore_endpoint =“/ custom / library / book”;@test void whongetbooksgivennoquery_thenallbooksshouldberturn(){给定()。contentType(contentType.json).when()。get(bookstore_endpoint).then()。stattycode(200).body(“size()”,是(2))。身体(“标题”,HastITEMS(“基金会”,“沙丘”));}}

我们可以从中看到@testprofile.注释,此测试将使用CustomTestProfile它将使HTTP请求在配置文件中覆盖的自定义端点getconfigoverrides.方法。此外,它将使用配置的替代书籍存储库实现getEnabledaltern方法。最后,通过使用自定义档案定义getconfigprofile.,它将持续存在于文件中而不是内存中的数据。

有一点要注意的是在执行此测试之前,Quarkus将关闭,然后使用新配置文件重新启动.这增加了一些时间,因为关机/重启发生,但它是额外的灵活性所支付的价格。

8.测试本地可执行文件

Quarkus提供了测试本机可执行文件的可能性。让我们创建一个本机映像测试:

@NativeImageTest @QuarkusTestResource(H2DatabaseTestResource.class)

现在,通过跑步:

mvn验证-Pnative

我们将看到构建本机映像并对其运行测试。

@nativeMageGETEST.注释指示Quarkus对本机映像运行此测试,而@quarkuststresource.在测试开始之前,将将一个H2实例启动到单独的过程中。随着数据库引擎未嵌入本机图像,需要对本机可执行文件进行测试所需的后者。

@QuarkustStresource.例如,注释也可用于开始自定义服务,例如TestContainers。我们需要做的就是实施Quarkustestresourcelifecyclemanager.接口并向我们进行注释我们的测试:

@quarkustestresource(yorcustomresourceimpl.class)

你需要一个GraalVM用于构建本机映像

此外,请注意,此刻,注射不适用于本机图像测试。本身运行的唯一运行是Quarkus应用程序,而不是测试本身

9.结论

在本文中,我们看到了如何做到这一点Quarkus为测试提供了极好的支持我们的应用程序。从简单的依赖管理、注入和模拟,到更复杂的配置文件和本地映像,Quarkus为我们提供了许多工具来创建强大而干净的测试。

一如既往,完整的代码可用在GitHub

通用的底部

使用Spring 5和Spring Boot 2开始,通过学习春天课程:

>>查看课程
对这篇文章的评论关闭!