Skip to content

Commit 0d67a63

Browse files
committed
4.x: Ability to Inject MockBeans in Helidon #7694
Signed-off-by: Jorge Bescos Gascon <[email protected]>
1 parent a3c04f7 commit 0d67a63

File tree

6 files changed

+149
-2
lines changed

6 files changed

+149
-2
lines changed

microprofile/testing/junit5/pom.xml

+5
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,11 @@
5454
<artifactId>junit-jupiter-api</artifactId>
5555
<scope>provided</scope>
5656
</dependency>
57+
<dependency>
58+
<groupId>org.mockito</groupId>
59+
<artifactId>mockito-core</artifactId>
60+
<scope>provided</scope>
61+
</dependency>
5762
<dependency>
5863
<groupId>io.helidon.jersey</groupId>
5964
<artifactId>helidon-jersey-client</artifactId>

microprofile/testing/junit5/src/main/java/io/helidon/microprofile/testing/junit5/HelidonJunitExtension.java

+35-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2020, 2023 Oracle and/or its affiliates.
2+
* Copyright (c) 2020, 2024 Oracle and/or its affiliates.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -28,6 +28,7 @@
2828
import java.util.ArrayList;
2929
import java.util.Arrays;
3030
import java.util.HashMap;
31+
import java.util.HashSet;
3132
import java.util.List;
3233
import java.util.Map;
3334
import java.util.Set;
@@ -48,7 +49,10 @@
4849
import jakarta.enterprise.inject.spi.CDI;
4950
import jakarta.enterprise.inject.spi.Extension;
5051
import jakarta.enterprise.inject.spi.InjectionPoint;
52+
import jakarta.enterprise.inject.spi.ProcessAnnotatedType;
5153
import jakarta.enterprise.inject.spi.ProcessInjectionPoint;
54+
import jakarta.enterprise.inject.spi.WithAnnotations;
55+
import jakarta.enterprise.inject.spi.configurator.AnnotatedFieldConfigurator;
5256
import jakarta.enterprise.inject.spi.configurator.AnnotatedTypeConfigurator;
5357
import jakarta.enterprise.util.AnnotationLiteral;
5458
import jakarta.inject.Inject;
@@ -73,6 +77,7 @@
7377
import org.junit.jupiter.api.extension.ParameterResolutionException;
7478
import org.junit.jupiter.api.extension.ParameterResolver;
7579
import org.junit.jupiter.api.extension.ReflectiveInvocationContext;
80+
import org.mockito.Mockito;
7681

7782

7883
/**
@@ -288,6 +293,11 @@ private void validatePerTest() {
288293
+ " injection into fields or constructor is not supported, as each"
289294
+ " test method uses a different CDI container. Field " + field
290295
+ " is annotated with @Inject");
296+
} else if (field.getAnnotation(MockBean.class) != null) {
297+
throw new RuntimeException("When a class is annotated with @HelidonTest(resetPerTest=true),"
298+
+ " injection into fields or constructor is not supported, as each"
299+
+ " test method uses a different CDI container. Field " + field
300+
+ " is annotated with @MockBean");
291301
}
292302
}
293303

@@ -298,6 +308,11 @@ private void validatePerTest() {
298308
+ " injection into fields or constructor is not supported, as each"
299309
+ " test method uses a different CDI container. Field " + field
300310
+ " is annotated with @Inject");
311+
} else if (field.getAnnotation(MockBean.class) != null) {
312+
throw new RuntimeException("When a class is annotated with @HelidonTest(resetPerTest=true),"
313+
+ " injection into fields or constructor is not supported, as each"
314+
+ " test method uses a different CDI container. Field " + field
315+
+ " is annotated with @MockBean");
301316
}
302317
}
303318
}
@@ -504,6 +519,7 @@ private static class AddBeansExtension implements Extension {
504519
private final List<AddBean> addBeans;
505520

506521
private final HashMap<String, Annotation> socketAnnotations = new HashMap<>();
522+
private final Set<Class<?>> mocks = new HashSet<>();
507523

508524
private AddBeansExtension(Class<?> testClass, List<AddBean> addBeans) {
509525
this.testClass = testClass;
@@ -521,7 +537,18 @@ void processSocketInjectionPoints(@Observes ProcessInjectionPoint<?, WebTarget>
521537
break;
522538
}
523539
}
540+
}
524541

542+
void processMockBean(@Observes @WithAnnotations(MockBean.class) ProcessAnnotatedType<?> obj) throws Exception {
543+
var configurator = obj.configureAnnotatedType();
544+
for (AnnotatedFieldConfigurator<?> field : configurator.fields()) {
545+
MockBean mockBean = field.getAnnotated().getAnnotation(MockBean.class);
546+
if (mockBean != null) {
547+
Field f = field.getAnnotated().getJavaMember();
548+
Class<?> fieldType = f.getType();
549+
mocks.add(fieldType);
550+
}
551+
}
525552
}
526553

527554
void registerOtherBeans(@Observes AfterBeanDiscovery event) {
@@ -543,6 +570,13 @@ void registerOtherBeans(@Observes AfterBeanDiscovery event) {
543570
.scope(ApplicationScoped.class)
544571
.createWith(context -> getWebTarget(client, "@default"));
545572

573+
// Register all mocks
574+
mocks.forEach(type -> {
575+
event.addBean()
576+
.addType(type)
577+
.scope(ApplicationScoped.class)
578+
.createWith(inst -> Mockito.mock(type));
579+
});
546580
}
547581

548582
@SuppressWarnings("unchecked")
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
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+
17+
package io.helidon.microprofile.testing.junit5;
18+
19+
import java.lang.annotation.ElementType;
20+
import java.lang.annotation.Retention;
21+
import java.lang.annotation.RetentionPolicy;
22+
import java.lang.annotation.Target;
23+
24+
/**
25+
* A field annotated with @MockBean will be mocked by Mockito
26+
* and injected in every place it is referenced.
27+
*/
28+
@Target({ElementType.FIELD})
29+
@Retention(RetentionPolicy.RUNTIME)
30+
public @interface MockBean {
31+
}

microprofile/testing/junit5/src/main/java/module-info.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2020, 2023 Oracle and/or its affiliates.
2+
* Copyright (c) 2020, 2024 Oracle and/or its affiliates.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -24,6 +24,7 @@
2424
requires io.helidon.microprofile.cdi;
2525
requires jakarta.inject;
2626
requires org.junit.jupiter.api;
27+
requires org.mockito;
2728

2829
requires transitive jakarta.cdi;
2930
requires transitive jakarta.ws.rs;

microprofile/tests/testing/junit5/pom.xml

+5
Original file line numberDiff line numberDiff line change
@@ -55,5 +55,10 @@
5555
<artifactId>hamcrest-core</artifactId>
5656
<scope>test</scope>
5757
</dependency>
58+
<dependency>
59+
<groupId>org.mockito</groupId>
60+
<artifactId>mockito-core</artifactId>
61+
<scope>test</scope>
62+
</dependency>
5863
</dependencies>
5964
</project>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
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+
17+
package io.helidon.microprofile.tests.testing.junit5;
18+
19+
import static org.hamcrest.CoreMatchers.is;
20+
import static org.hamcrest.MatcherAssert.assertThat;
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 io.helidon.microprofile.testing.junit5.AddBean;
28+
import io.helidon.microprofile.testing.junit5.HelidonTest;
29+
import io.helidon.microprofile.testing.junit5.MockBean;
30+
31+
import org.junit.jupiter.api.Test;
32+
import org.mockito.Mockito;
33+
34+
@HelidonTest
35+
@AddBean(TestMockBean.Resource.class)
36+
//@AddBean(TestMockBean.Service.class)
37+
public class TestMockBean {
38+
39+
@Inject
40+
@MockBean
41+
private Service service;
42+
@Inject
43+
private WebTarget target;
44+
45+
@Test
46+
public void injectionTest() {
47+
Mockito.when(service.test()).thenReturn("Mocked");
48+
String response = target.path("/test").request().get(String.class);
49+
assertThat(response, is("Mocked"));
50+
}
51+
52+
@Path("/test")
53+
public static class Resource {
54+
55+
@Inject
56+
private Service service;
57+
58+
@GET
59+
public String test() {
60+
return service.test();
61+
}
62+
}
63+
64+
public static class Service {
65+
66+
public String test() {
67+
return "Not Mocked";
68+
}
69+
70+
}
71+
}

0 commit comments

Comments
 (0)