Skip to content

Commit abba8b5

Browse files
authored
4.x: Mocking documentation (#8787)
* Mock documentation * Helidon mock documentation --------- Signed-off-by: tvallin <[email protected]>
1 parent 5ba18fb commit abba8b5

File tree

9 files changed

+262
-9
lines changed

9 files changed

+262
-9
lines changed

docs/pom.xml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,10 @@
4343
<type>pom</type>
4444
<optional>true</optional>
4545
</dependency>
46+
<dependency>
47+
<groupId>org.mockito</groupId>
48+
<artifactId>mockito-core</artifactId>
49+
</dependency>
4650
<!-- snippets dependencies -->
4751
<dependency>
4852
<groupId>org.apache.activemq</groupId>

docs/src/main/asciidoc/mp/guides/testing-junit5.adoc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,7 @@ This guide demonstrated how to create tests for MicroProfile applications in a J
177177
Refer to the following references for additional information:
178178
179179
* https://junit.org/junit5/docs/current/user-guide/[JUnit 5 User Guide]
180-
* xref:../testing.adoc[Testing with JUnit 5]
180+
* xref:../testing/testing.adoc[Testing with JUnit 5]
181181
182182
183183

docs/src/main/asciidoc/mp/testing-ng.adoc renamed to docs/src/main/asciidoc/mp/testing/testing-ng.adoc

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
:description: Helidon Testing with TestNG
2121
:keywords: helidon, mp, test, testing, testng
2222
:feature-name: Testing with TestNG
23-
:rootdir: {docdir}/..
23+
:rootdir: {docdir}/../..
2424
2525
include::{rootdir}/includes/mp.adoc[]
2626
@@ -128,7 +128,7 @@ In the current example, Helidon container will be launched prior test. The _Bean
128128
[source,java]
129129
.Code sample
130130
----
131-
include::{sourcedir}/mp/TestingNgSnippets.java[tag=snippet_1, indent=0]
131+
include::{sourcedir}/mp/testing/TestingNgSnippets.java[tag=snippet_1, indent=0]
132132
----
133133
<1> Start the Helidon container.
134134
<2> Set disabled Bean Discovery for the current test class.
@@ -143,7 +143,7 @@ To test `@RequestScoped` bean with JaxRs support:
143143
[source,java]
144144
.Test `RequestScoped` bean
145145
----
146-
include::{sourcedir}/mp/TestingNgSnippets.java[tag=snippet_2, indent=0]
146+
include::{sourcedir}/mp/testing/TestingNgSnippets.java[tag=snippet_2, indent=0]
147147
----
148148
<1> Start the Helidon container.
149149
<2> Set disabled Bean discovery.

docs/src/main/asciidoc/mp/testing.adoc renamed to docs/src/main/asciidoc/mp/testing/testing.adoc

Lines changed: 69 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
:description: Helidon Testing with JUnit5
2323
:keywords: helidon, mp, test, testing, junit
2424
:feature-name: Testing with JUnit
25-
:rootdir: {docdir}/..
25+
:rootdir: {docdir}/../..
2626
2727
include::{rootdir}/includes/mp.adoc[]
2828
@@ -32,6 +32,7 @@ include::{rootdir}/includes/mp.adoc[]
3232
- <<Maven Coordinates, Maven Coordinates>>
3333
- <<Usage, Usage>>
3434
- <<Examples, Examples>>
35+
- <<Mock Support, Mock Support>>
3536
- <<Additional Information, Additional Information>>
3637
- <<Reference, Reference>>
3738
@@ -136,7 +137,7 @@ In the current example, Helidon container will be launched prior test. The _Bean
136137
[source,java]
137138
.Code sample
138139
----
139-
include::{sourcedir}/mp/TestingSnippets.java[tag=snippet_1, indent=0]
140+
include::{sourcedir}/mp/testing/TestingSnippets.java[tag=snippet_1, indent=0]
140141
----
141142
<1> Start the Helidon container.
142143
<2> Set disabled Bean Discovery for the current test class.
@@ -151,13 +152,78 @@ To test `@RequestScoped` bean with JaxRs support:
151152
[source,java]
152153
.Test `RequestScoped` bean
153154
----
154-
include::{sourcedir}/mp/TestingSnippets.java[tag=snippet_2, indent=0]
155+
include::{sourcedir}/mp/testing/TestingSnippets.java[tag=snippet_2, indent=0]
155156
----
156157
<1> Start the Helidon container.
157158
<2> Set disabled Bean discovery.
158159
<3> Add JaxRs support to the current test class.
159160
<4> Define a `RequestScoped` bean.
160161
162+
== Mock Support
163+
164+
This section describes how to mock objects using Helidon API and in a second phase, using pure CDI.
165+
166+
=== Helidon Mock Support
167+
168+
Helidon has its own API to use mocking with test classes annotated with `@HelidonTest`.
169+
170+
==== Maven Coordinates
171+
172+
To enable Helidon Mock Support add the following dependency to your project’s pom.xml.
173+
[source,xml]
174+
----
175+
<dependency>
176+
<groupId>io.helidon.microprofile.testing</groupId>
177+
<artifactId>helidon-microprofile-testing-mocking</artifactId>
178+
<scope>test</scope>
179+
</dependency>
180+
----
181+
182+
==== API
183+
184+
It consists of one annotation named `@MockBean`, designed to be used on fields and parameters. The implementation
185+
relies only on CDI and thus it works with either JUnit or TestNG. The annotation has a parameter `answers` used
186+
to set the default answer for the mocked beans.
187+
188+
==== Example
189+
190+
[source,java]
191+
.Code sample
192+
----
193+
include::{sourcedir}/mp/testing/HelidonMockingSnippets.java[tag=snippet_1, indent=0]
194+
----
195+
<1> `service` field annotated with `@MockBean` and `Answers.CALLS_REAL_METHODS` for default answers.
196+
<2> Test the mocked service with real method response.
197+
<3> Test the mocked service with modified behavior.
198+
199+
=== Mocking objects with pure CDI
200+
201+
CDI can be used to enable mocking, the following example shows how to mock a service and inject it in a JAX-RS resource.
202+
Let's consider a simple service `FooService` with a dummy method `FooService#getFoo` that return `foo` as a `String`.
203+
And a resource where the service is injected and expose an endpoint at `/foo` that get the `String` provided by the service.
204+
205+
[source,java]
206+
.Code sample
207+
----
208+
include::{sourcedir}/mp/testing/CDIMockingSnippets.java[tag=snippet_1, indent=0]
209+
----
210+
<1> A simple `foo` Service.
211+
<2> Inject the service into the resource.
212+
213+
This example uses Mockito to create mock instances before each test. The method mockFooService is a CDI producer method
214+
that adds the mock instance as an @Alternative in order to replace the FooService singleton.
215+
216+
[source,java]
217+
.Code sample
218+
----
219+
include::{sourcedir}/mp/testing/CDIMockingSnippets.java[tag=snippet_2, indent=0]
220+
----
221+
<1> Set priority to 1 because of `@Alternative`.
222+
<2> Set `fooService` to a new mock before each tests.
223+
<3> This makes `FooResource` inject the mock instead of the default singleton.
224+
<4> Test that the mock is injected with modified behavior.
225+
<5> Test the real method behavior.
226+
161227
== Additional Information
162228
163229
* https://medium.com/helidon/testing-helidon-9df2ea14e22[Official blog article about Helidon and JUnit usage]

docs/src/main/asciidoc/sitegen.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -277,6 +277,7 @@ backend:
277277
value: "analytics"
278278
- type: "MENU"
279279
title: "Testing"
280+
dir: "testing"
280281
glyph:
281282
type: "icon"
282283
value: "thumbs_up_down"
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
/*
2+
* Copyright (c) 2024 Oracle and/or its affiliates.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package io.helidon.docs.mp.testing;
17+
18+
import io.helidon.microprofile.testing.junit5.HelidonTest;
19+
20+
import jakarta.annotation.Priority;
21+
import jakarta.enterprise.context.ApplicationScoped;
22+
import jakarta.enterprise.inject.Alternative;
23+
import jakarta.inject.Inject;
24+
import jakarta.ws.rs.GET;
25+
import jakarta.ws.rs.Path;
26+
import jakarta.ws.rs.Produces;
27+
import jakarta.ws.rs.client.WebTarget;
28+
import jakarta.ws.rs.core.Response;
29+
30+
import org.junit.jupiter.api.BeforeEach;
31+
import org.junit.jupiter.api.Test;
32+
import org.mockito.Answers;
33+
import org.mockito.Mockito;
34+
35+
import static org.hamcrest.MatcherAssert.assertThat;
36+
import static org.hamcrest.Matchers.is;
37+
import static org.mockito.Mockito.when;
38+
39+
@SuppressWarnings("ALL")
40+
class CDIMockingSnippets {
41+
42+
// tag::snippet_1[]
43+
@ApplicationScoped
44+
public class FooService { // <1>
45+
46+
public String getFoo() {
47+
return "foo";
48+
}
49+
}
50+
51+
@Path("/foo")
52+
public class FooResource {
53+
54+
@Inject
55+
private FooService fooService; // <2>
56+
57+
@GET
58+
public String getFoo() {
59+
return fooService.getFoo();
60+
}
61+
}
62+
// end::snippet_1[]
63+
64+
// tag::snippet_2[]
65+
@HelidonTest
66+
@Priority(1) // <1>
67+
class FooTest {
68+
69+
@Inject
70+
private WebTarget target;
71+
72+
private FooService fooService;
73+
74+
@BeforeEach
75+
void initMock() {
76+
fooService = Mockito.mock(FooService.class, Answers.CALLS_REAL_METHODS); // <2>
77+
}
78+
79+
@Produces
80+
@Alternative
81+
FooService mockFooService() {
82+
return fooService; // <3>
83+
}
84+
85+
@Test
86+
void testMockedService() {
87+
when(fooService.getFoo()).thenReturn("bar"); // <4>
88+
89+
Response response = target.path("/foo").request().get();
90+
91+
assertThat(response.getStatus(), is(200));
92+
assertThat(response.readEntity(String.class), is("bar"));
93+
}
94+
95+
@Test
96+
void testService() {
97+
Response response = target.path("/foo").request().get(); // <5>
98+
99+
assertThat(response.getStatus(), is(200));
100+
assertThat(response.readEntity(String.class), is("foo"));
101+
}
102+
}
103+
// end::snippet_2[]
104+
}
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
/*
2+
* Copyright (c) 2024 Oracle and/or its affiliates.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package io.helidon.docs.mp.testing;
17+
18+
import io.helidon.microprofile.testing.junit5.AddBean;
19+
import io.helidon.microprofile.testing.junit5.HelidonTest;
20+
import io.helidon.microprofile.testing.mocking.MockBean;
21+
22+
import jakarta.inject.Inject;
23+
import jakarta.ws.rs.GET;
24+
import jakarta.ws.rs.Path;
25+
import jakarta.ws.rs.client.WebTarget;
26+
27+
import org.junit.jupiter.api.Test;
28+
import org.mockito.Answers;
29+
import org.mockito.Mockito;
30+
31+
import static org.hamcrest.MatcherAssert.assertThat;
32+
import static org.hamcrest.Matchers.is;
33+
34+
@SuppressWarnings("ALL")
35+
class HelidonMockingSnippets {
36+
37+
// tag::snippet_1[]
38+
@HelidonTest
39+
@AddBean(MockBeanAnswerTest.Resource.class)
40+
@AddBean(MockBeanAnswerTest.Service.class)
41+
class MockBeanAnswerTest {
42+
43+
@MockBean(answer = Answers.CALLS_REAL_METHODS) // <1>
44+
private Service service;
45+
@Inject
46+
private WebTarget target;
47+
48+
@Test
49+
void injectionTest() {
50+
String response = target.path("/test").request().get(String.class);
51+
assertThat(response, is("Not Mocked")); // <2>
52+
Mockito.when(service.test()).thenReturn("Mocked");
53+
response = target.path("/test").request().get(String.class);
54+
assertThat(response, is("Mocked")); // <3>
55+
}
56+
57+
@Path("/test")
58+
public static class Resource {
59+
60+
@Inject
61+
private Service service;
62+
63+
@GET
64+
public String test() {
65+
return service.test();
66+
}
67+
}
68+
69+
static class Service {
70+
71+
String test() {
72+
return "Not Mocked";
73+
}
74+
75+
}
76+
}
77+
// end::snippet_1[]
78+
}

docs/src/main/java/io/helidon/docs/mp/TestingNgSnippets.java renamed to docs/src/main/java/io/helidon/docs/mp/testing/TestingNgSnippets.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
* See the License for the specific language governing permissions and
1414
* limitations under the License.
1515
*/
16-
package io.helidon.docs.mp;
16+
package io.helidon.docs.mp.testing;
1717

1818
import io.helidon.microprofile.config.ConfigCdiExtension;
1919
import io.helidon.microprofile.testing.testng.AddBean;

docs/src/main/java/io/helidon/docs/mp/TestingSnippets.java renamed to docs/src/main/java/io/helidon/docs/mp/testing/TestingSnippets.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
* See the License for the specific language governing permissions and
1414
* limitations under the License.
1515
*/
16-
package io.helidon.docs.mp;
16+
package io.helidon.docs.mp.testing;
1717

1818
import io.helidon.microprofile.config.ConfigCdiExtension;
1919
import io.helidon.microprofile.testing.junit5.AddBean;

0 commit comments

Comments
 (0)