All Downloads are FREE. Search and download functionalities are using the official Maven repository.

se.testing.adoc Maven / Gradle / Ivy

///////////////////////////////////////////////////////////////////////////////

    Copyright (c) 2023, 2024 Oracle and/or its affiliates.

    Licensed under the Apache License, Version 2.0 (the "License");
    you may not use this file except in compliance with the License.
    You may obtain a copy of the License at

        http://www.apache.org/licenses/LICENSE-2.0

    Unless required by applicable law or agreed to in writing, software
    distributed under the License is distributed on an "AS IS" BASIS,
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    See the License for the specific language governing permissions and
    limitations under the License.

///////////////////////////////////////////////////////////////////////////////

= Helidon Testing
:h1Prefix: SE
:pagename: Helidon Testing
:description: Testing in Helidon
:keywords: helidon, test, testing, junit
:feature-name: Helidon Testing Framework
:rootdir: {docdir}/..

include::{rootdir}/includes/se.adoc[]

== Contents

- <>
- <>
- <>
- <>
- <>
- <>

== Overview

Helidon provides built-in test support for Helidon testing with JUnit 5.

include::{rootdir}/includes/dependencies.adoc[]
[source,xml]
----

     io.helidon.webserver.testing.junit5
     helidon-webserver-testing-junit5
     test

----

== Usage

Helidon provides a rich set of extensions based on JUnit 5 for Helidon WebServer testing. Testing can be done with automatic server start-up, configuration, and shutdown. Testing can also be done without full server start-up with `DirectClient` when no real sockets are created.

== API

There are two main annotations that you can use to test Helidon WebServer.

* `@ServerTest` is an integration test annotation that starts the server (opens ports) and provides client injection pre-configured for the server port(s).
* `@RoutingTest` is a unit test annotation that does not start the server and does not open ports but provides a direct client (with the same API as the usual network client) to test routing.

The additional annotation `@Socket` can be used to qualify the injection of parameters into test constructors or methods, such as to obtain a client configured for the named socket.

The following table lists the supported types of parameters for the `@SetUpRoute` annotated methods. Such methods MUST be static
and may have any name. The `@SetUpRoute` annotation has `value` with socket name (to customize the setup for a different socket).

- Parameter type - supported class of a parameter
- Annotation - which annotations support this parameter
- Modules - which webserver extension modules support this signature

.Parameters for the `@SetUpRoute` annotated methods.
|===
|Parameter Type |Annotation |Modules |Notes

|`HttpRouting.Builder`
|`@ServerTest`, `@RoutingTest`
|
|

|`HttpRules`
|`@ServerTest`, `@RoutingTest`
|
|Same as `HttpRouting.Builder`, only routing setup

|`Router.RouterBuilder`
|`@ServerTest`, `@RoutingTest`
|
|

|`SocketListener.Builder`
|`@ServerTest`
|
|

|`WebSocketRouting.Builder`
|`@ServerTest`, `@RoutingTest`
|websocket
|

|===

In addition, a static method annotated with `@SetUpServer` can be defined for `@ServerTest`, which has a single parameter of link:{javadoc-base-url}/io.helidon.webserver/io/helidon/webserver/WebServerConfig.Builder.html[`WebServerConfig.Builder`].

The following table lists the injectable types (through constructor or method injection).

- Type - type that can be injected
- Socket - if checked, you can use the `@Socket` annotation to obtain a value specific to that named socket
- Annotation - which annotations support this injection
- Modules - which WebServer extension modules support this injection
- Notes - additional details

.Injectable types.
|===
|Type |Socket? |Annotation |Modules |Notes
|`WebServer`
|
|`@ServerTest`
|
|Server instance (already started)

|`URI`
|x
|`@ServerTest`
|
|URI pointing to a port of the webserver

|`SocketHttpClient`
|x
|`@ServerTest`
|
|This client allows you to send anything in order to test for bad requests or other issues.

|`Http1Client`
|x
|`@ServerTest`
|
|

|`DirectClient`
|x
|`@RoutingTest`
|
|Implements `Http1Client` API

|`WsClient`
|x
|`@ServerTest`
|websocket
|

|`DirectWsClient`
|x
|`@RoutingTest`
|websocket
|Implements `WsClient` API

|===


Extensions can enhance the features for the module `helidon-testing-junit5-webserver` to support additional protocols.


== Examples

You can create the following test to validate that the server returns the correct response:

.Basic Helidon test framework usage.
[source,java]
----
include::{sourcedir}/se/TestingSnippets.java[tag=snippet_1, indent=0]
----
<1> Use `@ServerTest` to trigger the testing framework.
<2> Inject `Http1Client` for the test.
<3> SetUp routing for the test.
<4> Regular `JUnit` test method.
<5> Call the `client` to obtain server response
<6> Perform the necessary assertions.

To trigger the framework to start and configure the server, annotate the testing class with the `@ServerTest` annotation.

In this test, the `Http1Client` client is used, which means that the framework will create, configure, and inject this object as a parameter to the constructor.

To set up routing, a static method annotated with `@SetUpRoute` is present. The framework uses this method to inject the configured routing to the subject of testing – in the current case, the `Quickstart` application.

As everything above is performed by the testing framework, regular unit tests can be done. After completing all tests, the testing framework will shut down the server.

=== Routing Tests

If there is no need to set up and run a server, a `DirectClient` client can be used. It is a testing client that bypasses HTTP transport and directly invokes the router.

.Routing test using `@RoutingTest` and `DirectClient`.
[source,java]
----
include::{sourcedir}/se/TestingSnippets.java[tag=snippet_2, indent=0]
----
<1> Use `@RoutingTest` to trigger the testing framework.
<2> Inject `DirectClient` for the test.
<3> SetUp routing for the test.
<4> A regular `JUnit` test method.
<5> Call the `client` to obtain server response.
<6> Perform  the necessary assertions.

If only routing tests are required, this is a "lighter" way of testing because the framework will not configure and run the full Helidon server. This way, no real ports will be opened. All the communication will be done through `DirectClient`, which makes the tests very effective.

It is required to annotate the test class with the `@RoutingTest` annotation to trigger the server to do the configuration. Thus, it will inject the DirectClient client, which can then be used in unit tests.

Routing is configured the same way as in full server testing using the `@SetUpRoute` annotation.

== Additional Information

=== WebSocket Testing

If WebSocket testing is required, there is an additional module for it. It is necessary to include the following Maven dependency to the Project's pom file:

[source,xml]
----

    io.helidon.testing.junit5
    helidon-testing-junit5-websocket
    test

----


=== WebSocket Testing Example

The WebSocket Testing extension adds support for routing configuration and injection of WebSocket related artifacts, such as WebSockets and DirectWsClient in Helidon unit tests.

.WebSocket sample test.
[source,java]
----
include::{sourcedir}/se/TestingSnippets.java[tag=snippet_3, indent=0]
----
<1> Declare `WsClient` and later inject it in the constructor.
<2> Using @SetUpRoute, create WebSocket routing and assign a serverside listener.
<3> Test the WebSocket endpoint using the regular @Test annotation.
<4> Create and assign the clientside listener.
<5> Check if the received message is correct.

.`ClientSideListener` helper class.
[source,java]
----
include::{sourcedir}/se/TestingSnippets.java[tag=snippet_4, indent=0]
----
<1> Send "Hello" when a connection is opened.
<2> Save the message when received and close the connection.
<3> React on an error.

The WebSocket `ClientSideListener` is also a helper class that implements `WsListener` and is very straightforward:

.`ServerSideListener` helper class.
[source,java]
----
include::{sourcedir}/se/TestingSnippets.java[tag=snippet_5, indent=0]
----
<1> Send "ws" on a received message.

The testing class should be annotated with `@RoutingTest` only if routing tests are required without real port opening. Instead of `WsClient`, use `DirectWsClient`.


== Reference

* https://junit.org/junit5/docs/current/user-guide/[JUnit 5 User Guide]




© 2015 - 2025 Weber Informatics LLC | Privacy Policy