Review HTTP-based testing in JVM mode

In the POM.xml file, there are two test dependencies:

`<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>`
Copy the code

The QuarkUS-junit5 test is required because it provides annotations for the @Quarkustest control test framework. Rest-assured is not required, but it is a convenient way to test HTTP endpoints, and provides integration capabilities that automatically set the correct URL, so no configuration is required.

Because you are using JUnit 5, you must set the version of the Surefire Maven plug-in because JUnit 5 is not supported by the default version:

`<plugin>`
 `<artifactId>maven-surefire-plugin</artifactId>`
 `<version>${surefire-plugin.version}</version>`
 `<configuration>`
 `<systemPropertyVariables>`
 `<java.util.logging.manager>org.jboss.logmanager.LogManager</java.util.logging.manager>`
 `<maven.home>${maven.home}</maven.home>`
 `</systemPropertyVariables>`
 `</configuration>`
`</plugin>`
Copy the code

Set Java. Util. Logging. The property manager system, to ensure that the test will use the right that the logmanager, and maven. Home to ensure that the ${maven. Home} / conf/Settings. The XML application from the custom configurations (if any).

The project should also include a simple test:

`package org.acme.getting.started.testing; ` `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)); ` ` `} ` `}Copy the code

This test directly tests our REST endpoint using HTTP. When a test is run, the application is started before the test is run.

1.1. Control test ports

Although Quarkus listens on port 8080 by default, it runs tests on port 8081 by default. This allows you to run tests while the application is running.

You can configure the port application. Properties for testing by configuring HTTP and quarkus.http. Test-ssl-porthttps in your quarkus.http.test-port server:

`quarkus.http.test-port=8083`
`quarkus.http.test-ssl-port=8446`
Copy the code

Quarkus also provides RestAssured integration, which configures the default ports used by RestAssured before running tests, so no additional configuration is required.

1.2. Control HTTP timeout

When REST Security was used in the tests, the connection and response timeout was set to 30 seconds. You can override this setting with the quarkus.http.test-timeout property:

quarkus.http.test-timeout=10s
Copy the code

1.3. Inject urIs

It is also possible to inject the URL directly into the test, making it easy to use other clients. This is done via the @testhttpresource annotation.

Write a simple test that shows how to load some static resources. Create a simple HTML file in SRC /main/resources/ meta-INF /resources/index.html:

`<html>`
 `<head>`
 `<title>Testing Guide</title>`
 `</head>`
 `<body>`
 `Information about testing`
 `</body>`
`</html>`
Copy the code

Create a simple test to ensure that it is provided correctly:

`package org.acme.getting.started.testing; ` `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")` `URL url; // This annotation allows you to inject the Quarkus instance URL directly, @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); ` ` `} ` `}Copy the code

Now @testhttpresource, you can inject URI, URL, and StringURL representations.

2. Test specific endpoints

RESTassured and @testhttpresource both allow you to specify the endpoint class to test, rather than a hard-coded path. This currently supports JAX-RS endpoints, servlets, and reactive routing. This makes it easier to see exactly which endpoints a given test is testing.

For the purposes of these examples, suppose you have an endpoint like this:

`@Path("/hello")` `public class GreetingResource {` `@GET` `@Produces(MediaType.TEXT_PLAIN)` `public String hello() {` `return "hello"; ` ` `} ` `}Copy the code

Currently, annotations for @applicationPath () to set the JAX-RS context path are not supported. Quarkus.resteasy. Path To customize the context path, use the config value instead.

2.1, TestHTTPResource

Can use io.quarkus.test.com mon. HTTP. TestHTTPEndpoint path annotations to specify the endpoint and then extracted from providing the endpoint of path. If you also specify a value for the TestHTTPResource endpoint, it will be appended to the end of the endpoint path.

`package org.acme.getting.started.testing; ` `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.TestHTTPEndpoint; ` `import io.quarkus.test.common.http.TestHTTPResource; ` `import io.quarkus.test.junit.QuarkusTest; ` `@QuarkusTest` `public class StaticContentTest {` `@TestHTTPEndpoint(GreetingResource.class)` `@TestHTTPResource` `URL  url; ` `@Test` `public void testIndexHtml() throws Exception {` `try (InputStream in = url.openStream()) {` `String contents = readStream(in); ` `Assertions.assertTrue(contents.equals("hello")); ` `}` `}` `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); ` ` `} ` `}Copy the code

Because GreetingResource uses annotations, @path (“/hello”) will end the injected URL with /hello.

2.2, RESTassured

The basic path to control RESTassured (i.e., as the default path from the root each request), you can use io.quarkus.test.com mon. HTTP. TestHTTPEndpoint comments. This can be applied at the class or method level. To test the greeting resource, we will do the following:

`package org.acme.getting.started.testing; ` `import io.quarkus.test.junit.QuarkusTest; ` `import io.quarkus.test.common.http.TestHTTPEndpoint; ` `import org.junit.jupiter.api.Test; ` `import java.util.UUID; ` `import static io.restassured.RestAssured.when; ` `import static org.hamcrest.CoreMatchers.is; "@quarkustest" "@testhttPendpoint (greetingResource.class) // This tells RESTAssured to prefix all requests /hello. ' 'public class GreetingResourceTest {' @test' 'public void testHelloEndpoint() {'' when().get() // Please note that there is no need to specify a path here, The default path/hello, is this test ` `. Then () ` `. StatusCode (200) ` `. Body (is) (" hello "); ` ` `} ` `}Copy the code

3. Injection test

Quarkus can Inject CDI beans into tests with the @Inject annotation (in fact, tests in Quarkus are full CDI beans, so you can use all CDI functionality). Create a simple test that tests the interface directly without using HTTP:

`package org.acme.getting.started.testing; ` `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 // This GreetingServicebean will be injected into the test GreetingService Service; ` `@Test` `public void testGreetingService() {` `Assertions.assertEquals("hello Quarkus", service.greeting("Quarkus")); ` ` `} ` `}Copy the code

4. Apply interceptors to tests

As mentioned above, the Quarkus tests are actually full CDI beans, so you can apply the CDI interceptor as usual. For example, if you want your test method to run in the context of a transaction, you can simply annotate the method with @Transactional, which will be processed by the transaction interceptor.

In addition, you can also create your own stereotypes. For example, you could create @transactionalQuarkustest as follows:

`@QuarkusTest`
`@Stereotype`
`@Transactional`
`@Retention(RetentionPolicy.RUNTIME)`
`@Target(ElementType.TYPE)`
`public @interface TransactionalQuarkusTest {`
`}`
Copy the code

If this annotation is then applied to the test class, it works just as well as if we applied both the @Quarkustest and @Transactional annotations, for example:

`@TransactionalQuarkusTest` `public class TestStereotypeTestCase {` `@Inject` `UserTransaction userTransaction; ` `@Test` `public void testUserTransaction() throws Exception {` `Assertions.assertEquals(Status.STATUS_ACTIVE, userTransaction.getStatus()); ` ` `} ` `}Copy the code

5. Tests and transactions

Standard Quarkus@Transactional annotations can be used on tests, but this means that changes made to the database by tests will be persistent. If you want to roll back at the end of the test of any changes, you can use the IO. Quarkus. Test. TestTransaction comments. This runs the test method in a transaction, but rolls it back to restore any database changes after the test method is complete.

6. Rich test callbacks

As an alternative or complement to interceptors, all @Quarkustest classes can be enriched by implementing the following callback interfaces:

  • io.quarkus.test.junit.callback.QuarkusTestBeforeClassCallback

  • io.quarkus.test.junit.callback.QuarkusTestAfterConstructCallback

  • io.quarkus.test.junit.callback.QuarkusTestBeforeEachCallback

  • io.quarkus.test.junit.callback.QuarkusTestAfterEachCallback

IO. Quarkus. Test. Junit. Callback. QuarkusTestBeforeAllCallback to support IO. Quarkus. Test. Junit. Callback. QuarkusTestAfterConstructCallbackQuarkus and abandoned the version, and will be in a future version of quarkus will be deleted

Such callback implementations must be registered with the defined “service provider” java.util.Serviceloader

For example, the following example callback:

`package org.acme.getting.started.testing; ` `import io.quarkus.test.junit.callback.QuarkusTestBeforeEachCallback; ` `import io.quarkus.test.junit.callback.QuarkusTestMethodContext; ` `public class MyQuarkusTestBeforeEachCallback implements QuarkusTestBeforeEachCallback {` `@Override` `public void beforeEach(QuarkusTestMethodContext context) {` `System.out.println("Executing " + context.getTestMethod()); ` ` `} ` `}Copy the code

Must pass the SRC/main/resources/meta-inf/services/IO quarkus. Test. Junit. Callback. QuarkusTestBeforeEachCallback registered with the following ways:

org.acme.getting.started.testing.MyQuarkusTestBeforeEachCallback
Copy the code
  • Comments can be read from the test class or method to control what the callback should do.
  • Although you can use a JUnit Jupiter callback interface like this BeforeEachCallback, you may encounter classloading problems because Quarkus must run tests in a custom classloader that JUnit does not know about

7. Test different Profiles

In all the examples so far, Quarkus has been started only once for all the tests. Quarkus will start before running the first test, then all tests will run, then Quarkus will shut down at the end. This provides a very fast testing experience, but is limited by the inability to test different configurations.

To solve this problem, Quarkus supports the idea of testing profiles. If the test has a different profile than the previously run test, Quarkus will be shut down and started with the new profile before running the test. This is obviously slower because it increases the close/start cycle of test time, but has a lot of flexibility.

  • To reduce the number of times Quarkus needs to restart, it is recommended that you put all tests that require a specific configuration file into their own package and then run the tests alphabetically.

7.1 edit a Profile

In order to realize the test configuration file, need to implement the IO. Quarkus. Test. Junit. QuarkusTestProfile:

`package org.acme.getting.started.testing; ` `import java.util.Collections; ` `import java.util.List; ` `import java.util.Map; ` `import java.util.Set; ` `import io.quarkus.test.junit.QuarkusTestProfile; ` `import io.quarkus.test.junit.QuarkusTestProfile.TestResourceEntry; ` `public class MockGreetingProfile implements QuarkusTestProfile {` `@Override` `public Map<String, String> getConfigOverrides() {' // This method enables configuration properties to be overridden. Here, you are changing the JAX-RS root path. ` `return Collections.singletonMap("quarkus.resteasy.path","/api"); ` `}` `@Override` `public Set<Class<? >> getEnabledAlternatives() {' // This method enables cdi@alternativeBean. This makes it easy to emulate some bean functionality. ` `return Collections.singleton(MockGreetingService.class); } @override // This can be used to change the configuration file. Because this default setting test does nothing, it is included for completeness. ` `public String getConfigProfile() {` `return "test"; ' '} ' '@override' 'public List<TestResourceEntry> testResources() {' // This method allows us to apply other things that only apply to this configuration file QuarkusTestResourceLifecycleManager class. If you don't override this method, ` ` / / is only use QuarkusTestResourceLifecycleManager by @ QuarkusTestResource class annotation enable class will be used in this configuration file is used to test ` ` / / (and not test the behavior of the same configuration file is used). ` `return Collections.singletonList(new TestResourceEntry(CustomWireMockServerManager.class)); ` ` `} ` `}Copy the code

Now that you have defined the configuration file, you need to include it in your test class. Using the @ TestProfile (MockGreetingProfile. Class).

All test profile configurations are stored in a single class, which makes it easy to tell if previous tests were run with the same configuration.

7.2. Run specific tests

Quarkus provides the ability to limit test execution to tests with specific @TestProfile annotations. By using the method of combined with system properties of tags to work QuarkusTestProfile quarkus. Test. Profile. The tags.

In essence, any QuarkusTestProfile has at least one matching labels to match the value of variable quarkus. Test. Profile. The tags, which will be considered and all with a configuration file comments @ TestProfile activity tests will be run, The rest of the tests will be skipped. This is best shown in the following example.

First, define some of these QuarkusTestProfile implementations:

`public class Profiles {` `public static class NoTags implements QuarkusTestProfile {` `}` `public static class SingleTag implements QuarkusTestProfile {` `@Override` `public Set<String> tags() {` `return Collections.singleton("test1"); ` `}` `}` `public static class MultipleTags implements QuarkusTestProfile {` `@Override` `public Set<String> tags() {` `return new HashSet<>(Arrays.asList("test1", "test2")); ` `} ` `} ` ` `}Copy the code

Now, suppose we have the following tests:

`@QuarkusTest`
`public class NoQuarkusProfileTest {`
 `@Test`
 `public void test() {`
 `// test something`
 `}`
`}`
Copy the code

@QuarkusTest @TestProfile(Profiles.NoTags.class) public class NoTagsTest { @Test public void test() { // test something }}

`@QuarkusTest`
`@TestProfile(Profiles.SingleTag.class)`
`public class SingleTagTest {`
 `@Test`
 `public void test() {`
 `// test something`
 `}`
`}`
Copy the code

@QuarkusTest @TestProfile(Profiles.MultipleTags.class) public class MultipleTagsTest { @Test public void test() { // test something } }

Consider the following scenario: * quarkus. Test. Profile. The tags is not set, will perform all the tests. * quarkus test. Profile. Tags = foo: in this case, will not perform any tests, because in QuarkusTestProfile implementation defined on all label does not match the value of the quarkus. Test. Profile. The tags. Note that NoQuarkusProfileTest also does not execute @testProfile because it does not use annotations. * quarkus test. Profile. Tags = test1: SingleTagTest under this situation, MultipleTagsTest will run, because their respective QuarkusTestProfile tag on the implementation and the value of the matching quarkus. Test. Profile. The tags. * quarkus test. Profile. Tags = test1, test3: this situation lead to perform the same as the former test. * quarkus test. Profile. Tags = test2 and test3: In this case, the only MultipleTagsTest will run, because the only QuarkusTestProfile MultipleTagsTest is achieved, the value of his tags method match quarkus. Test. Profile. The tags. ============ Quarkus supports using Mock objects in two different ways. You can use the CDI alternative to mock out a bean for all test classes, or QuarkusMock can mock out a bean per test. 8.1 CDI@Alternative mechanism. ====================== To use it, simply override the bean you want to emulate with a class in the SRC /test/ Java directory and add @alternative and @priority (1) annotations to the bean. Alternatively, a handy IO. Quarkus.test. Mock can use prototype annotations. This built-in stereotype declares @alternative, @priority (1), and @Dependent. For example, there are these services:Copy the code

@ApplicationScoped public class ExternalService { public String service() { return “external”; }}

It can be simulated in the following class SRC /test/ Java:Copy the code

@mock @applicationScoped // overrides the scope @mock declared on the @dependent stereotype. public class MockExternalService extends ExternalService { @Override public String service() { return “mock”; }}

It is important that the alternative appear in the SRC /test/ Java directory instead of SRC /main/ Java, because otherwise the alternative will always be available, not just at test time. Please note that this method is not currently available for testing native images, as this would require baking test alternatives into native images. 8.2, use QuarkusMock simulation = = = = = = = = = = = = = = = = = = =. IO quarkus. Test. Junit. QuarkusMock class can be used to simulate any temporary Bean of the normal range. If you use this method in a method, @beforeall The simulation will be in effect for all tests of the current class, whereas if you use this method in a test method, the simulation will be in effect only during the current test. This method can be used with any normal scope CDI bean (e.g. @ApplicationScoped, @RequestScoped, etc., basically every scope @Dependent except @Singleton and so on). Examples of usage are as follows:Copy the code

@QuarkusTest public class MockTestCase { @Inject MockableBean1 mockableBean1; @Inject MockableBean2 mockableBean2; @BeforeAll public static void setup() { MockableBean1 mock = Mockito.mock(MockableBean1.class); Mockito.when(mock.greet(“Stuart”)).thenReturn(“A mock for Stuart”); QuarkusMock.installMockForType(mock, MockableBean1.class); // Since the injected instance installMockForType cannot be used here, So the mock method can be used for both Test methods} @test public void testBeforeAll() {assertEquals(“A mock for Stuart”, mockableBean1.greet(“Stuart”)); Assertions.assertEquals(“Hello Stuart”, mockableBean2.greet(“Stuart”)); } @test public void testPerTestMock() {//installMockForInstance is used to replace the injected bean, which is valid during the Test method. QuarkusMock.installMockForInstance(new BonjourGreeter(), mockableBean2); Assertions.assertEquals(“A mock for Stuart”, mockableBean1.greet(“Stuart”)); Assertions.assertEquals(“Bonjour Stuart”, mockableBean2.greet(“Stuart”)); } @ApplicationScoped public static class MockableBean1 { public String greet(String name) { return “Hello ” + name; } } @ApplicationScoped public static class MockableBean2 { public String greet(String name) { return “Hello ” + name; } } public static class BonjourGreeter extends MockableBean2 { @Override public String greet(String name) { return “Bonjour ” + name; }}}

Note that it does not rely on Mockito, can use any simulation library you like, and can even override objects manually to provide the desired behavior. 8.2.1, further simplify @ InjectMock = = = = = = = = = = = = = = = = = = = = = = QuarkusMockQuarkus on the basis of function, It also allows users to effortlessly leverage Mockito to emulate the bean QuarkusMock supported by Mockito. Through the dependencies are available in @ IO. Quarkus. Test. Junit. Mockito. InjectMock comments to use this feature quarkus junit5 -- mockito. Using @injectMock, the previous example could have been written as follows:Copy the code

@QuarkusTest public class MockTestCase { @InjectMock MockableBean1 mockableBean1; @InjectMock MockableBean2 mockableBean2; @BeforeEach public void setup() { Mockito.when(mockableBean1.greet(“Stuart”)).thenReturn(“A mock for Stuart”); } @Test public void firstTest() { Assertions.assertEquals(“A mock for Stuart”, mockableBean1.greet(“Stuart”)); Assertions.assertEquals(null, mockableBean2.greet(“Stuart”)); } @Test public void secondTest() { Mockito.when(mockableBean2.greet(“Stuart”)).thenReturn(“Bonjour Stuart”); Assertions.assertEquals(“A mock for Stuart”, mockableBean1.greet(“Stuart”)); Assertions.assertEquals(“Bonjour Stuart”, mockableBean2.greet(“Stuart”)); } @ApplicationScoped public static class MockableBean1 { public String greet(String name) { return “Hello ” + name; } } @ApplicationScoped public static class MockableBean2 { public String greet(String name) { return “Hello ” + name; }}}

* @InjectMock causes the mock to exist and be available in the test method of the test class (other test classes do not affect this) * in mockableBean1 this is configured for each test method of the class * Since mockableBean2 has not configured the mock, it will return the default Mockito response. * In this test, mockableBean2 is configured, so it will return the configured response. While the above test does a good job of showing the functionality @InjectMock, it is not a good representation of the real test. In a real test, you would probably configure a mock, but then test a bean that uses the mock bean. Here's an example:Copy the code

@QuarkusTest public class MockGreetingServiceTest { @InjectMock GreetingService greetingService; @Test public void testGreeting() { when(greetingService.greet()).thenReturn(“hi”); given() .when().get(“/greeting”) .then() .statusCode(200) .body(is(“hi”)); // Because greetingService is configured as GreetingResource using a GreetingServicebean emulation, // we get a mock response instead of a regular GreetingServicebean response. } @Path(“greeting”) public static class GreetingResource { final GreetingService greetingService; public GreetingResource(GreetingService greetingService) { this.greetingService = greetingService; } @GET @Produces(“text/plain”) public String greet() { return greetingService.greet(); } } @ApplicationScoped public static class GreetingService { public String greet(){ return “hello”; }}}

8.2.2, used in @ InjectSpy soon not mock = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = in InjectMockQuarkus providing function, on the basis of Quarkus also allows users to use Mockito effortlessly to monitor bean QuarkusMock supported by Mockito. Through the dependencies are available in @ IO. Quarkus. Test. Junit. Mockito. InjectSpy comments to use this feature quarkus junit5 -- mockito. Sometimes, when testing, you just need to verify that a logical path is being taken, or you just need to stub the response of a single method while executing the rest of the methods on the Spied clone. See the Mockito documentation for more details on the Spy part of the simulation. In both cases, it is best to use spy objects. Using @InjectSpy, the previous example could have been written as follows:Copy the code

@QuarkusTest public class SpyGreetingServiceTest { @InjectSpy GreetingService greetingService; @Test public void testDefaultGreeting() { given() .when().get(“/greeting”) .then() .statusCode(200) .body(is(“hello”)); Mockito.verify(greetingService, Mockito.times(1)).greet(); // Just make sure the GreetingService test calls the greet method for us and does not overwrite it. } @Test public void testOverrideGreeting() { when(greetingService.greet()).thenReturn(“hi”); // Tell the spy to return “hi” instead of “hello”. When GreetingResource requests a greeting from GreetingService, // gets a mock response instead of the regular GreetingServiceBean response. given() .when().get(“/greeting”) .then() .statusCode(200) .body(is(“hi”)); // Verifying that a mock response was received from the spy. } @Path(“greeting”) public static class GreetingResource { final GreetingService greetingService; public GreetingResource(GreetingService greetingService) { this.greetingService = greetingService; } @GET @Produces(“text/plain”) public String greet() { return greetingService.greet(); } } @ApplicationScoped public static class GreetingService { public String greet(){ return “hello”; }}}

8.2.3, using the @ InjectMock with @ RestClient = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = the @ RegisterRestClient register register rest at runtime - the realization of the client, And because beans need to be general scoped, you must use the annotation interface @ApplicationScoped.Copy the code

@Path("/") @ApplicationScoped @RegisterRestClient public interface GreetingService { @GET @Path("/hello") @Produces(MediaType.TEXT_PLAIN) String hello(); }

For the test class, here is an example:Copy the code

@quarkustest public class GreetingResourceTest {@injectMock @restClient // indicates the instance RestClient that this injection point is intended to use. GreetingService greetingService; @Test public void testHelloEndpoint() { Mockito.when(greetingService.hello()).thenReturn(“hello from mockito”); given() .when().get(“/hello”) .then() .statusCode(200) .body(is(“hello from mockito”)); }}

9. Start services before The Quarkus application starts A very common requirement is to start certain services that the Quarkus application depends on before the Quarkus application starts testing. To meet this need, Quarkus provides @ io.quarkus.test.com. Mon mon QuarkusTestResource and io.quarkus.test.com. QuarkusTestResourceLifecycleManager. By simply using annotations any test in the test suite @ QuarkusTestResource, Quarkus will run QuarkusTestResourceLifecycleManager any test run before the corresponding test. Test suites can also free use multiple @ QuarkusTestResource notation, in this case, all corresponding QuarkusTestResourceLifecycleManager object will run before test. When multiple test resources are used, they can be started simultaneously. To do this, you need to set @quarkustestResource (parallel = true). Test resources are global, even if they are defined on a test class or custom profile, meaning that all tests will activate them even if we do remove duplicates. If you only want to enable test resources on a single test class or test configuration file, you can use @QuarkustestResource (restrictToAnnotatedClass = True). Quarkus provides some ready-made QuarkusTestResourceLifecycleManager (please refer to the IO. Quarkus. Test. H2. H2DatabaseTestResource which launched the h2 database, Or IO. Quarkus. Test. Kubernetes. Client. KubernetesMockServerTestResource kubernetes API server), which launched the simulation But it is common to create custom implementations to meet specific application requirements. Common cases include starting a Docker container using Testcontainers (examples can be found here), or starting a mock HTTP server using Wiremock (examples can be found here). 9.1 Annotation-based Test Resources ============= You can write test resources that are enabled and configured with annotations. This annotation can be enabled by placing @QuarkustestResource on the annotation, which will be used to enable and configure the test resource. For example, it defines the @ WithKubernetesTestServer comments, you can use the comments to activate KubernetesServerTestResource in the test, but only for the annotated test class. You can also place them in the QuarkusTestProfile test profile.Copy the code

@QuarkusTestResource(KubernetesServerTestResource.class) @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) public @interface WithKubernetesTestServer { /** * Start it with HTTPS */ boolean https() default false; /** * Start it in CRUD mode */ boolean crud() default true; /** * Port to use, defaults to any available port */ int port() default 0; }

This KubernetesServerTestResource class must implement QuarkusTestResourceConfigurableLifecycleManager annotations to use the previous configuration interface:Copy the code

public class KubernetesServerTestResource implements QuarkusTestResourceConfigurableLifecycleManager<WithKubernetesTestServer> { private boolean https = false; private boolean crud = true; private int port = 0; @Override public void init(WithKubernetesTestServer annotation) { this.https = annotation.https(); this.crud = annotation.crud(); this.port = annotation.port(); } // ... }

10. Hang detection ======= @quarkustest supports hang detection to help diagnose any unexpected hangs. If no progress is made within the specified time (that is, no JUnit callback is invoked), Quarkus prints a stack trace to the console to help diagnose the hang. The default value for this timeout is 10 minutes. No further action will be taken, and testing will continue normally (usually until the CI times out), but the printed stack trace should help diagnose the cause of the build failure. You can control this timeout using the quarkus.test.hang-detection-timeout system property (you can also set it in application.properties, but the timeout will not be read until Quarkus is started, So Quarkus startup timeout will default to 10 minutes). 11. Native executable tests ========== can also be used to test native executable @nativeImagetest. It supports all of the features mentioned in this guide, with the exception of injection testing (the native executable runs in a separate non-JVM process, which is virtually impossible). 12. Use @QuarkusIntegrationTest ============================ @QuarkusIntegrationTest should be used to start and test Quarkus build artifacts and support test JARS (of any type), Native image or container image. In short, this means that if the Quarkus build (MVN Package or Gradle Build) results in a JAR, that JAR will be used as a startup, java-jar... And test it. Conversely, if a native image is built, the application will be started./ Application... Run the tests again against the running application. In the end, If a container image is created during the build process (using an extension including quarkus-container-image-jib or quarkus-container-image-docker) and Quarkus.container-image.build =true with properties configured), the container will be created and run (this requires the presence of a Docker executable). Like @NativeImagetest, this is a black box test that supports the same Settings functionality and has the same limitations. ! [cloud native - Quarkus test application] (HTTP: / / https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/a9c562fb9f054962bad96ee3e548af20~tplv-k3u1fbpfcp-z oom-1.image)Copy the code