Skip to content

Commit 3d0890a

Browse files
committed
New module mock-beans
Signed-off-by: Jorge Bescos Gascon <[email protected]>
1 parent 8e9d040 commit 3d0890a

File tree

19 files changed

+177
-172
lines changed

19 files changed

+177
-172
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-mock-beans</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-mock-beans</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

-6
Original file line numberDiff line numberDiff line change
@@ -54,11 +54,6 @@
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>
6257
<dependency>
6358
<groupId>io.helidon.jersey</groupId>
6459
<artifactId>helidon-jersey-client</artifactId>
@@ -72,7 +67,6 @@
7267
<artifactId>hamcrest-core</artifactId>
7368
<scope>test</scope>
7469
</dependency>
75-
7670
</dependencies>
7771

7872
</project>

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

+2-76
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@
3131
import java.util.ArrayList;
3232
import java.util.Arrays;
3333
import java.util.HashMap;
34-
import java.util.HashSet;
3534
import java.util.List;
3635
import java.util.Map;
3736
import java.util.Properties;
@@ -49,16 +48,11 @@
4948
import jakarta.enterprise.inject.se.SeContainer;
5049
import jakarta.enterprise.inject.se.SeContainerInitializer;
5150
import jakarta.enterprise.inject.spi.AfterBeanDiscovery;
52-
import jakarta.enterprise.inject.spi.AnnotatedParameter;
53-
import jakarta.enterprise.inject.spi.Bean;
54-
import jakarta.enterprise.inject.spi.BeanManager;
5551
import jakarta.enterprise.inject.spi.BeforeBeanDiscovery;
5652
import jakarta.enterprise.inject.spi.CDI;
5753
import jakarta.enterprise.inject.spi.Extension;
5854
import jakarta.enterprise.inject.spi.InjectionPoint;
59-
import jakarta.enterprise.inject.spi.ProcessAnnotatedType;
6055
import jakarta.enterprise.inject.spi.ProcessInjectionPoint;
61-
import jakarta.enterprise.inject.spi.WithAnnotations;
6256
import jakarta.enterprise.inject.spi.configurator.AnnotatedTypeConfigurator;
6357
import jakarta.enterprise.util.AnnotationLiteral;
6458
import jakarta.inject.Inject;
@@ -83,8 +77,6 @@
8377
import org.junit.jupiter.api.extension.ParameterResolutionException;
8478
import org.junit.jupiter.api.extension.ParameterResolver;
8579
import org.junit.jupiter.api.extension.ReflectiveInvocationContext;
86-
import org.mockito.MockSettings;
87-
import org.mockito.Mockito;
8880

8981

9082
/**
@@ -302,11 +294,6 @@ private void validatePerTest() {
302294
+ " injection into fields or constructor is not supported, as each"
303295
+ " test method uses a different CDI container. Field " + field
304296
+ " is annotated with @Inject");
305-
} else if (field.getAnnotation(MockBean.class) != null) {
306-
throw new RuntimeException("When a class is annotated with @HelidonTest(resetPerTest=true),"
307-
+ " injection into fields or constructor is not supported, as each"
308-
+ " test method uses a different CDI container. Field " + field
309-
+ " is annotated with @MockBean");
310297
}
311298
}
312299

@@ -317,11 +304,6 @@ private void validatePerTest() {
317304
+ " injection into fields or constructor is not supported, as each"
318305
+ " test method uses a different CDI container. Field " + field
319306
+ " is annotated with @Inject");
320-
} else if (field.getAnnotation(MockBean.class) != null) {
321-
throw new RuntimeException("When a class is annotated with @HelidonTest(resetPerTest=true),"
322-
+ " injection into fields or constructor is not supported, as each"
323-
+ " test method uses a different CDI container. Field " + field
324-
+ " is annotated with @MockBean");
325307
}
326308
}
327309
}
@@ -548,13 +530,13 @@ private static class AddBeansExtension implements Extension {
548530
private final List<AddBean> addBeans;
549531

550532
private final HashMap<String, Annotation> socketAnnotations = new HashMap<>();
551-
private final Set<Class<?>> mocks = new HashSet<>();
552533

553534
private AddBeansExtension(Class<?> testClass, List<AddBean> addBeans) {
554535
this.testClass = testClass;
555536
this.addBeans = addBeans;
556537
}
557538

539+
558540
void processSocketInjectionPoints(@Observes ProcessInjectionPoint<?, WebTarget> event) throws Exception{
559541
InjectionPoint injectionPoint = event.getInjectionPoint();
560542
Set<Annotation> qualifiers = injectionPoint.getQualifiers();
@@ -565,36 +547,10 @@ void processSocketInjectionPoints(@Observes ProcessInjectionPoint<?, WebTarget>
565547
break;
566548
}
567549
}
568-
}
569550

570-
void processMockBean(@Observes @WithAnnotations(MockBean.class) ProcessAnnotatedType<?> obj) throws Exception {
571-
var configurator = obj.configureAnnotatedType();
572-
configurator.fields().forEach(field -> {
573-
MockBean mockBean = field.getAnnotated().getAnnotation(MockBean.class);
574-
if (mockBean != null) {
575-
Field f = field.getAnnotated().getJavaMember();
576-
// Adds @Inject to be more user friendly
577-
field.add(Literal.INSTANCE);
578-
Class<?> fieldType = f.getType();
579-
mocks.add(fieldType);
580-
}
581-
});
582-
configurator.constructors().forEach(constructor -> {
583-
processMockBeanParameters(constructor.getAnnotated().getParameters());
584-
});
585-
}
586-
587-
private void processMockBeanParameters(List<? extends AnnotatedParameter<?>> parameters) {
588-
parameters.stream().forEach(parameter -> {
589-
MockBean mockBean = parameter.getAnnotation(MockBean.class);
590-
if (mockBean != null) {
591-
Class<?> parameterType = parameter.getJavaParameter().getType();
592-
mocks.add(parameterType);
593-
}
594-
});
595551
}
596552

597-
void registerOtherBeans(@Observes AfterBeanDiscovery event, BeanManager beanManager) {
553+
void registerOtherBeans(@Observes AfterBeanDiscovery event) {
598554

599555
Client client = ClientBuilder.newClient();
600556

@@ -613,25 +569,6 @@ void registerOtherBeans(@Observes AfterBeanDiscovery event, BeanManager beanMana
613569
.scope(ApplicationScoped.class)
614570
.createWith(context -> getWebTarget(client, "@default"));
615571

616-
// Register all mocks
617-
mocks.forEach(type -> {
618-
event.addBean()
619-
.addType(type)
620-
.scope(ApplicationScoped.class)
621-
.alternative(true)
622-
.createWith(inst -> {
623-
Set<Bean<?>> beans = beanManager.getBeans(MockSettings.class);
624-
if (!beans.isEmpty()) {
625-
Bean<?> bean = beans.iterator().next();
626-
MockSettings mockSettings = (MockSettings) beanManager.getReference(bean, MockSettings.class,
627-
beanManager.createCreationalContext(null));
628-
return Mockito.mock(type, mockSettings);
629-
} else {
630-
return Mockito.mock(type);
631-
}
632-
})
633-
.priority(0);
634-
});
635572
}
636573

637574
@SuppressWarnings("unchecked")
@@ -830,15 +767,4 @@ public Class<? extends Extension> value() {
830767
}
831768
}
832769

833-
/**
834-
* Supports inline instantiation of the {@link Inject} annotation.
835-
*/
836-
private static final class Literal extends AnnotationLiteral<Inject> implements Inject {
837-
838-
private static final Literal INSTANCE = new Literal();
839-
840-
@Serial
841-
private static final long serialVersionUID = 1L;
842-
843-
}
844770
}

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

-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@
2424
requires io.helidon.microprofile.cdi;
2525
requires jakarta.inject;
2626
requires org.junit.jupiter.api;
27-
requires org.mockito;
2827

2928
requires transitive jakarta.cdi;
3029
requires transitive jakarta.ws.rs;
+47
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
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-mock-beans</artifactId>
30+
<name>Helidon Microprofile Testing Mock Beans</name>
31+
32+
<description>
33+
Integration with Mock Beans to support tests with CDI injection
34+
</description>
35+
36+
<dependencies>
37+
<dependency>
38+
<groupId>io.helidon.microprofile.cdi</groupId>
39+
<artifactId>helidon-microprofile-cdi</artifactId>
40+
</dependency>
41+
<dependency>
42+
<groupId>org.mockito</groupId>
43+
<artifactId>mockito-core</artifactId>
44+
</dependency>
45+
</dependencies>
46+
47+
</project>

microprofile/testing/junit5/src/main/java/io/helidon/microprofile/testing/junit5/MockBean.java renamed to microprofile/testing/mock-beans/src/main/java/io/helidon/microprofile/testing/mockbeans/MockBean.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
* limitations under the License.
1515
*/
1616

17-
package io.helidon.microprofile.testing.junit5;
17+
package io.helidon.microprofile.testing.mockbeans;
1818

1919
import java.lang.annotation.ElementType;
2020
import java.lang.annotation.Retention;
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.mockbeans;
17+
18+
import jakarta.enterprise.context.ApplicationScoped;
19+
import jakarta.enterprise.event.Observes;
20+
import jakarta.enterprise.inject.literal.InjectLiteral;
21+
import jakarta.enterprise.inject.spi.AfterBeanDiscovery;
22+
import jakarta.enterprise.inject.spi.AnnotatedParameter;
23+
import jakarta.enterprise.inject.spi.Bean;
24+
import jakarta.enterprise.inject.spi.BeanManager;
25+
import jakarta.enterprise.inject.spi.Extension;
26+
import jakarta.enterprise.inject.spi.ProcessAnnotatedType;
27+
import jakarta.enterprise.inject.spi.WithAnnotations;
28+
29+
import java.lang.reflect.Field;
30+
import java.util.HashSet;
31+
import java.util.List;
32+
import java.util.Set;
33+
34+
import org.mockito.MockSettings;
35+
import org.mockito.Mockito;
36+
37+
/**
38+
* CDI extension for Mock Beans implementation.
39+
*/
40+
public class MockBeansCdiExtension implements Extension {
41+
42+
private final Set<Class<?>> mocks = new HashSet<>();
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.add(fieldType);
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.add(parameterType);
67+
}
68+
});
69+
}
70+
71+
void registerOtherBeans(@Observes AfterBeanDiscovery event, BeanManager beanManager) {
72+
// Register all mocks
73+
mocks.forEach(type -> {
74+
event.addBean()
75+
.addType(type)
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(type, mockSettings);
85+
} else {
86+
return Mockito.mock(type);
87+
}
88+
})
89+
.priority(0);
90+
});
91+
}
92+
}

0 commit comments

Comments
 (0)