Skip to content

Commit 4f8043d

Browse files
authored
4.x: Ability to Inject MockBeans in Helidon #7694 (#8674)
* 4.x: Ability to Inject MockBeans in Helidon #7694 Signed-off-by: Jorge Bescos Gascon <[email protected]>
1 parent e3d8a35 commit 4f8043d

File tree

19 files changed

+609
-4
lines changed

19 files changed

+609
-4
lines changed

all/pom.xml

+4
Original file line numberDiff line numberDiff line change
@@ -773,6 +773,10 @@
773773
<groupId>io.helidon.messaging.mock</groupId>
774774
<artifactId>helidon-messaging-mock</artifactId>
775775
</dependency>
776+
<dependency>
777+
<groupId>io.helidon.microprofile.testing</groupId>
778+
<artifactId>helidon-microprofile-testing-mocking</artifactId>
779+
</dependency>
776780
<dependency>
777781
<groupId>io.helidon.logging</groupId>
778782
<artifactId>helidon-logging-common</artifactId>

bom/pom.xml

+5
Original file line numberDiff line numberDiff line change
@@ -1028,6 +1028,11 @@
10281028
<artifactId>helidon-messaging-mock</artifactId>
10291029
<version>${helidon.version}</version>
10301030
</dependency>
1031+
<dependency>
1032+
<groupId>io.helidon.microprofile.testing</groupId>
1033+
<artifactId>helidon-microprofile-testing-mocking</artifactId>
1034+
<version>${helidon.version}</version>
1035+
</dependency>
10311036
<!-- Logging -->
10321037
<dependency>
10331038
<groupId>io.helidon.logging</groupId>

dependencies/pom.xml

+6
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
<version.lib.animal-sniffer>1.18</version.lib.animal-sniffer>
4141
<version.lib.annotation-api>1.3.5</version.lib.annotation-api>
4242
<version.lib.brave-opentracing>1.0.0</version.lib.brave-opentracing>
43+
<version.lib.bytebuddy>1.14.14</version.lib.bytebuddy>
4344
<version.lib.commons-codec>1.16.0</version.lib.commons-codec>
4445
<version.lib.commons-logging>1.2</version.lib.commons-logging>
4546
<version.lib.cron-utils>9.1.6</version.lib.cron-utils>
@@ -501,6 +502,11 @@
501502
</exclusion>
502503
</exclusions>
503504
</dependency>
505+
<dependency>
506+
<groupId>net.bytebuddy</groupId>
507+
<artifactId>byte-buddy</artifactId>
508+
<version>${version.lib.bytebuddy}</version>
509+
</dependency>
504510
<dependency>
505511
<groupId>jakarta.websocket</groupId>
506512
<artifactId>jakarta.websocket-api</artifactId>

microprofile/testing/junit5/pom.xml

-1
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,6 @@
6767
<artifactId>hamcrest-core</artifactId>
6868
<scope>test</scope>
6969
</dependency>
70-
7170
</dependencies>
7271

7372
</project>

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

+1-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.

microprofile/testing/mocking/pom.xml

+49
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!--
3+
Copyright (c) 2024 Oracle and/or its affiliates.
4+
5+
Licensed under the Apache License, Version 2.0 (the "License");
6+
you may not use this file except in compliance with the License.
7+
You may obtain a copy of the License at
8+
9+
http://www.apache.org/licenses/LICENSE-2.0
10+
11+
Unless required by applicable law or agreed to in writing, software
12+
distributed under the License is distributed on an "AS IS" BASIS,
13+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
See the License for the specific language governing permissions and
15+
limitations under the License.
16+
-->
17+
18+
<project xmlns="http://maven.apache.org/POM/4.0.0"
19+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
20+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
21+
<modelVersion>4.0.0</modelVersion>
22+
<parent>
23+
<groupId>io.helidon.microprofile.testing</groupId>
24+
<artifactId>helidon-microprofile-testing-project</artifactId>
25+
<version>4.0.0-SNAPSHOT</version>
26+
<relativePath>../pom.xml</relativePath>
27+
</parent>
28+
29+
<artifactId>helidon-microprofile-testing-mocking</artifactId>
30+
<name>Helidon Microprofile Testing Mocking</name>
31+
32+
<description>
33+
Integration with Mocking to support tests with CDI injection
34+
</description>
35+
36+
<dependencies>
37+
<dependency>
38+
<groupId>jakarta.enterprise</groupId>
39+
<artifactId>jakarta.enterprise.cdi-api</artifactId>
40+
<scope>provided</scope>
41+
</dependency>
42+
<dependency>
43+
<groupId>org.mockito</groupId>
44+
<artifactId>mockito-core</artifactId>
45+
<scope>provided</scope>
46+
</dependency>
47+
</dependencies>
48+
49+
</project>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
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.mocking;
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+
import org.mockito.Answers;
25+
26+
/**
27+
* A field annotated with @MockBean will be mocked by Mockito
28+
* and injected in every place it is referenced.
29+
*/
30+
@Retention(RetentionPolicy.RUNTIME)
31+
@Target({ElementType.FIELD, ElementType.PARAMETER})
32+
public @interface MockBean {
33+
34+
/**
35+
* The {@link Answers} type to use on the mock.
36+
* Defaults to {@link Answers#RETURNS_DEFAULTS}
37+
* @return the answer type
38+
*/
39+
Answers answer() default Answers.RETURNS_DEFAULTS;
40+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
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.microprofile.testing.mocking;
17+
18+
import java.lang.reflect.Field;
19+
import java.util.HashMap;
20+
import java.util.List;
21+
import java.util.Map;
22+
import java.util.Set;
23+
24+
import jakarta.enterprise.context.ApplicationScoped;
25+
import jakarta.enterprise.event.Observes;
26+
import jakarta.enterprise.inject.literal.InjectLiteral;
27+
import jakarta.enterprise.inject.spi.AfterBeanDiscovery;
28+
import jakarta.enterprise.inject.spi.AnnotatedParameter;
29+
import jakarta.enterprise.inject.spi.Bean;
30+
import jakarta.enterprise.inject.spi.BeanManager;
31+
import jakarta.enterprise.inject.spi.Extension;
32+
import jakarta.enterprise.inject.spi.ProcessAnnotatedType;
33+
import jakarta.enterprise.inject.spi.WithAnnotations;
34+
import org.mockito.MockSettings;
35+
import org.mockito.Mockito;
36+
37+
/**
38+
* CDI extension for Mocking implementation.
39+
*/
40+
public class MockBeansCdiExtension implements Extension {
41+
42+
private final Map<Class<?>, MockBean> mocks = new HashMap<>();
43+
44+
void processMockBean(@Observes @WithAnnotations(MockBean.class) ProcessAnnotatedType<?> obj) throws Exception {
45+
var configurator = obj.configureAnnotatedType();
46+
configurator.fields().forEach(field -> {
47+
MockBean mockBean = field.getAnnotated().getAnnotation(MockBean.class);
48+
if (mockBean != null) {
49+
Field f = field.getAnnotated().getJavaMember();
50+
// Adds @Inject to be more user friendly
51+
field.add(InjectLiteral.INSTANCE);
52+
Class<?> fieldType = f.getType();
53+
mocks.put(fieldType, mockBean);
54+
}
55+
});
56+
configurator.constructors().forEach(constructor -> {
57+
processMockBeanParameters(constructor.getAnnotated().getParameters());
58+
});
59+
}
60+
61+
private void processMockBeanParameters(List<? extends AnnotatedParameter<?>> parameters) {
62+
parameters.stream().forEach(parameter -> {
63+
MockBean mockBean = parameter.getAnnotation(MockBean.class);
64+
if (mockBean != null) {
65+
Class<?> parameterType = parameter.getJavaParameter().getType();
66+
mocks.put(parameterType, mockBean);
67+
}
68+
});
69+
}
70+
71+
void registerOtherBeans(@Observes AfterBeanDiscovery event, BeanManager beanManager) {
72+
// Register all mocks
73+
mocks.entrySet().forEach(entry -> {
74+
event.addBean()
75+
.addType(entry.getKey())
76+
.scope(ApplicationScoped.class)
77+
.alternative(true)
78+
.createWith(inst -> {
79+
Set<Bean<?>> beans = beanManager.getBeans(MockSettings.class);
80+
if (!beans.isEmpty()) {
81+
Bean<?> bean = beans.iterator().next();
82+
MockSettings mockSettings = (MockSettings) beanManager.getReference(bean, MockSettings.class,
83+
beanManager.createCreationalContext(null));
84+
return Mockito.mock(entry.getKey(), mockSettings);
85+
} else {
86+
return Mockito.mock(entry.getKey(), Mockito.withSettings().defaultAnswer(entry.getValue().answer()));
87+
}
88+
})
89+
.priority(0);
90+
});
91+
}
92+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
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+
/**
18+
* Helidon implementation of mocking.
19+
*/
20+
package io.helidon.microprofile.testing.mocking;
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+
/**
18+
* Mock Beans extension module to run CDI tests.
19+
*/
20+
module io.helidon.microprofile.testing.mocking {
21+
22+
requires jakarta.inject;
23+
requires org.mockito;
24+
25+
requires transitive jakarta.cdi;
26+
27+
exports io.helidon.microprofile.testing.mocking;
28+
29+
provides jakarta.enterprise.inject.spi.Extension
30+
with io.helidon.microprofile.testing.mocking.MockBeansCdiExtension;
31+
}

microprofile/testing/pom.xml

+1
Original file line numberDiff line numberDiff line change
@@ -35,5 +35,6 @@
3535
<modules>
3636
<module>junit5</module>
3737
<module>testng</module>
38+
<module>mocking</module>
3839
</modules>
3940
</project>

microprofile/testing/testng/pom.xml

-1
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,6 @@
5757
<groupId>io.helidon.config</groupId>
5858
<artifactId>helidon-config-yaml-mp</artifactId>
5959
</dependency>
60-
6160
<dependency>
6261
<groupId>org.testng</groupId>
6362
<artifactId>testng</artifactId>

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2022, 2023 Oracle and/or its affiliates.
2+
* Copyright (c) 2022, 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.

microprofile/tests/testing/junit5/pom.xml

+10
Original file line numberDiff line numberDiff line change
@@ -55,5 +55,15 @@
5555
<artifactId>hamcrest-core</artifactId>
5656
<scope>test</scope>
5757
</dependency>
58+
<dependency>
59+
<groupId>io.helidon.microprofile.testing</groupId>
60+
<artifactId>helidon-microprofile-testing-mocking</artifactId>
61+
<scope>test</scope>
62+
</dependency>
63+
<dependency>
64+
<groupId>org.mockito</groupId>
65+
<artifactId>mockito-core</artifactId>
66+
<scope>test</scope>
67+
</dependency>
5868
</dependencies>
5969
</project>

0 commit comments

Comments
 (0)