Skip to content

Commit

Permalink
Merge pull request #24295 from gsmet/command-mode-mocking
Browse files Browse the repository at this point in the history
Add some details about how to mock CDI beans in command mode tests
gsmet authored Mar 14, 2022

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
2 parents a44856b + fe71d38 commit f0fd5f8
Showing 3 changed files with 104 additions and 15 deletions.
88 changes: 85 additions & 3 deletions docs/src/main/asciidoc/command-mode-reference.adoc
Original file line number Diff line number Diff line change
@@ -124,9 +124,30 @@ in order to unblock the main thread and initiate the shutdown process.

=== Development Mode

Also for command mode applications the dev mode is supported. When you run `mvn quarkus:dev`, the command mode application is executed.
Also for command mode applications the dev mode is supported.
When you start your application in dev mode, the command mode application is executed:

As command mode applications will often require arguments to be passed on the commandline, this is also possible in dev mode via the `quarkus.args` system property. For example `mvn quarkus:dev -Dquarkus.args='--help'` and the same can be achieved with Gradle: `./gradlew quarkusDev --quarkus-args='--help'`.
include::includes/devtools/dev.adoc[]

As command mode applications will often require arguments to be passed on the command line, this is also possible in dev mode:

[source, bash, subs=attributes+, role="primary asciidoc-tabs-sync-cli"]
.CLI
----
quarkus dev '--help'
----

[source, bash, subs=attributes+, role="secondary asciidoc-tabs-sync-maven"]
.Maven
----
./mvnw quarkus:dev -Dquarkus.args='--help'
----

[source, bash, subs=attributes+, role="secondary asciidoc-tabs-sync-gradle"]
.Gradle
----
./gradlew quarkusDev --quarkus-args='--help'
----

You should see the following down the bottom of the screen after the application is stopped:

@@ -189,5 +210,66 @@ import io.quarkus.test.junit.main.QuarkusMainIntegrationTest;
@QuarkusMainIntegrationTest
public class HelloIT extends HelloTest {
}
----

=== Mocking

CDI injection is not supported in the `@QuarkusMainTest` tests.
Consequently, mocking CDI beans with `QuarkusMock` or `@InjectMock` is not supported either.

It is possible to mock CDI beans by leveraging xref:getting-started-testing.adoc#testing_different_profiles[test profiles] though.

For instance, in the following test, the singleton `CdiBean1` will be mocked by `MockedCdiBean1`:

[source,java]
----
package org.acme.commandmode.test;
import java.util.Set;
import javax.enterprise.inject.Alternative;
import javax.inject.Singleton;
import org.junit.jupiter.api.Test;
import org.acme.commandmode.test.MyCommandModeTest.MyTestProfile;
import io.quarkus.test.junit.QuarkusTestProfile;
import io.quarkus.test.junit.TestProfile;
import io.quarkus.test.junit.main.Launch;
import io.quarkus.test.junit.main.LaunchResult;
import io.quarkus.test.junit.main.QuarkusMainTest;
@QuarkusMainTest
@TestProfile(MyTestProfile.class)
public class MyCommandModeTest {
@Test
@Launch(value = {})
public void testLaunchCommand(LaunchResult result) {
// ... assertions ...
}
public static class MyTestProfile implements QuarkusTestProfile {
@Override
public Set<Class<?>> getEnabledAlternatives() {
return Set.of(MockedCdiBean1.class); <1>
}
}
@Alternative <2>
@Singleton <3>
public static class MockedCdiBean1 implements CdiBean1 {
@Override
public String myMethod() {
return "mocked value";
}
}
}
----
<1> List all the CDI beans for which you want to enable an alternative mocked bean.
<2> Use `@Alternative` without a `@Priority`. Make sure you don't use `@Mock`.
<3> The scope of the mocked bean should be consistent with the original one.

----
Using this pattern, you can enable specific alternatives for any given test.
29 changes: 18 additions & 11 deletions docs/src/main/asciidoc/getting-started-testing.adoc
Original file line number Diff line number Diff line change
@@ -493,7 +493,7 @@ import java.util.Set;
import io.quarkus.test.junit.QuarkusTestProfile;
import io.quarkus.test.junit.QuarkusTestProfile.TestResourceEntry;
public class MockGreetingProfile implements QuarkusTestProfile {
public class MockGreetingProfile implements QuarkusTestProfile { <1>
/**
* Returns additional config to be applied to the test. This
@@ -539,15 +539,16 @@ public class MockGreetingProfile implements QuarkusTestProfile {
*/
@Override
public List<TestResourceEntry> testResources() {
return Collections.singletonList(new TestResourceEntry(CustomWireMockServerManager.class)); <4>
return Collections.singletonList(new TestResourceEntry(CustomWireMockServerManager.class));
}
/**
* If this is returns true then only the test resources returned from {@link #testResources()} will be started,
* If this returns true then only the test resources returned from {@link #testResources()} will be started,
* global annotated test resources will be ignored.
*/
default boolean disableGlobalTestResources() {
@Override
public boolean disableGlobalTestResources() {
return false;
}
@@ -557,37 +558,43 @@ public class MockGreetingProfile implements QuarkusTestProfile {
* then Quarkus will only execute tests that are annotated with a {@code @TestProfile} that has at least one of the
* supplied (via the aforementioned system property) tags.
*/
default Set<String> tags() {
@Override
public Set<String> tags() {
return Collections.emptySet();
}
/**
* The command line parameters that are passed to the main method on startup.
*/
default String[] commandLineParameters() {
@Override
public String[] commandLineParameters() {
return new String[0];
}
/**
* If the main method should be run
* If the main method should be run.
*/
default boolean runMainMethod() {
@Override
public boolean runMainMethod() {
return false;
}
/**
* If this method returns true then all {@code StartupEvent} and {@code ShutdownEvent} observers declared on application
* beans should be disabled.
*/
default boolean disableApplicationLifecycleObservers() {
@Override
public boolean disableApplicationLifecycleObservers() {
return false;
}
}
----
<1> All these methods have default implementations so just override the ones you need to override.

Now we have defined our profile we need to include it on our test class. We do this with `@TestProfile(MockGreetingProfile.class)`.
Now we have defined our profile we need to include it on our test class.
We do this by annotating the test class with `@TestProfile(MockGreetingProfile.class)`.

All the test profile config is stored in a single class, which makes it easy to tell if the previous test ran with the
All the test profile configuration is stored in a single class, which makes it easy to tell if the previous test ran with the
same configuration.

=== Running specific tests
Original file line number Diff line number Diff line change
@@ -57,7 +57,7 @@ default List<TestResourceEntry> testResources() {
}

/**
* If this is returns true then only the test resources returned from {@link #testResources()} will be started,
* If this returns true then only the test resources returned from {@link #testResources()} will be started,
* global annotated test resources will be ignored.
*/
default boolean disableGlobalTestResources() {

0 comments on commit f0fd5f8

Please sign in to comment.