Skip to content

Commit

Permalink
documentation
Browse files Browse the repository at this point in the history
  • Loading branch information
musketyr committed Mar 19, 2021
1 parent 693a56b commit fec332d
Show file tree
Hide file tree
Showing 9 changed files with 140 additions and 31 deletions.
53 changes: 51 additions & 2 deletions docs/guide/src/docs/asciidoc/index.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
[.ribbon]
image::ribbon.png[link={project-url}]

Gru is HTTP interaction testing framework with out-of-box support for Grails, Spring MVC, API Gateway but it can be used with any
HTTP server such as Micronaut embedded server.
Gru is HTTP interaction testing framework with out-of-box support for Micronaut, Grails, Spring MVC, API Gateway but it can be used with any
HTTP server framework.

== Installation

Expand All @@ -23,12 +23,14 @@ dependencies {
testCompile "com.agorapulse:gru-grails:{project-version}" // <2>
testCompile "com.agorapulse:gru-spring:{project-version}" // <3>
testCompile "com.agorapulse:gru-api-gateway:{project-version}" // <4>
testCompile "com.agorapulse:gru-micronaut:{project-version}" // <5>
}
----
<1> HTTP module for any HTTP backend such as Micronaut embedded server
<2> Grails module to emulate HTTP interaction within Grails Unit tests
<3> Spring module to emulate HTTP interaction using `MockMvc`
<4> AWS API Gateway module for HTTP proxy lambdas
<5> Micronaut module for running HTTP request against the embedded server

[NOTE]
====
Expand All @@ -55,6 +57,53 @@ include::{root-dir}/examples/heist/src/test/groovy/heist/HttpSpec.groovy[lines=1
<2> Set the base URL `http://despicableme.wikia.com` for HTTP calls
<3> Execute HTTP GET request on `/wiki/Felonius_Gru` URI and verify it is accessible and returns `OK(200)` status code.

=== Micronaut

Micronaut plays well with `@MicronautTest` annotation. If you are using `@MicronautTest` you can simply inject
`Gru` instance into your test.

.Using @Inject with @MicronautTest
[source,groovy]
----
include::{root-dir}/examples/heist-micronaut/src/test/groovy/heist/InjectNativeMicronautSpec.groovy[lines=18..-1]
----
<1> Annotate your test with @MicronautTest`
<2> Inject `Gru`

Alternatively, you can let `Gru` to create default `ApplicationContext` for you.

.Using Default Application Context
[source,groovy]
----
include::{root-dir}/examples/heist-micronaut/src/test/groovy/heist/AutomaticMicronautSpec.groovy[lines=18..-1]
----
<1> Create a simple `Micronaut` client for `Gru`
<2> Default application context is created and fields can be injected into the test

If you construct the application context yourself then you need to point `Gru` to the field of type `ApplicationContext`.

.Using a Custom Application Context
[source,groovy]
----
include::{root-dir}/examples/heist-micronaut/src/test/groovy/heist/ManualWithSimpleProviderMicronautSpec.groovy[lines=18..-1]
----
<1> Point `Gru` to field `context` holding the custom `ApplicationContext` instance

NOTE: As an alternative, you can make your test class implement `io.micronaut.context.ApplicationContextProvider`.

Gru can actually help you create the custom context:

.Creating a Custom Application Context
[source,groovy]
----
include::{root-dir}/examples/heist-micronaut/src/test/groovy/heist/AdvancedAutomaticMicronautSpec.groovy[lines=18..-1]
----
<1> Declare any field you want to reference from the context before `Gru` declaration
<2> Customize the `ApplicationContextBuilder`
<3> Customize the `ApplicationContext` itself, e.g. register mocks
<4> Start the application and injects fields into the test automatically
<5> The field can be automatically injected

=== Grails

Gru for Grails tests controllers in context of other Grails artifacts such as url mappings or interceptors.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,17 +29,17 @@ import javax.inject.Inject

class AdvancedAutomaticMicronautSpec extends Specification {

MoonService moonService = Mock()
MoonService moonService = Mock() // <1>

@AutoCleanup Gru gru = Gru.create(
Micronaut.build(this) {
environments 'my-custom-env'
environments 'my-custom-env' // <2>
}.then {
registerSingleton(MoonService, moonService)
}.start(true)
registerSingleton(MoonService, moonService) // <3>
}.start() // <4>
)

@Inject Environment environment
@Inject Environment environment // <5>

void 'test it works'() {
expect:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,22 @@ package heist

import com.agorapulse.gru.Gru
import com.agorapulse.gru.micronaut.Micronaut
import io.micronaut.context.env.Environment
import spock.lang.AutoCleanup
import spock.lang.Specification

import javax.inject.Inject

class AutomaticMicronautSpec extends Specification {

@AutoCleanup Gru gru = Gru.create(Micronaut.create(this))
@AutoCleanup Gru gru = Gru.create(Micronaut.create(this)) // <1>

@Inject Environment environment // <2>

void 'test it works'() {
expect:
'test' in environment.activeNames
and:
gru.test {
get '/moons/earth/moon'
expect {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,10 @@ import spock.lang.Specification

import javax.inject.Inject

@MicronautTest
@MicronautTest // <1>
class InjectNativeMicronautSpec extends Specification {

@Inject Gru gru
@Inject Gru gru // <2>

void 'test it works'() {
expect:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,13 @@ package heist
import com.agorapulse.gru.Gru
import com.agorapulse.gru.micronaut.Micronaut
import io.micronaut.context.ApplicationContext
import io.micronaut.context.ApplicationContextProvider
import io.micronaut.runtime.server.EmbeddedServer
import spock.lang.AutoCleanup
import spock.lang.Specification

class ManualWithSimpleProviderMicronautSpec extends Specification {

@AutoCleanup Gru gru = Gru.create(Micronaut.create(this) { context })
@AutoCleanup Gru gru = Gru.create(Micronaut.create(this) { context }) // <1>

@AutoCleanup ApplicationContext context
@AutoCleanup EmbeddedServer embeddedServer
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,26 +22,25 @@
import io.micronaut.context.ApplicationContext;
import io.micronaut.context.annotation.Bean;
import io.micronaut.context.annotation.Factory;
import io.micronaut.context.annotation.Requires;

import javax.inject.Singleton;
import java.util.Optional;

/**
* Factory which creates Gru instance for the classes annotated with @MicronautTest.
*/
@Factory
@Requires(property = GruFactory.TEST_CLASS_PROPERTY_NAME)
public class GruFactory {

private static final String TEST_CLASS_PROPERTY_NAME = "micronaut.test.active.spec.clazz";
public static final String TEST_CLASS_PROPERTY_NAME = "micronaut.test.active.spec.clazz";

@Singleton
@Bean(preDestroy = "close")
@SuppressWarnings({"rawtypes", "unchecked"})
@SuppressWarnings({"rawtypes"})
Gru<Client> gru(ApplicationContext context) {
Optional<Class> maybeTestClass = context.getProperty(TEST_CLASS_PROPERTY_NAME, Class.class);

if (!maybeTestClass.isPresent()) {
return null;
}

return Gru.create(Micronaut.createLazy(() -> context.getBean(maybeTestClass.get()), () -> context));
Class testClass = context.getRequiredProperty(TEST_CLASS_PROPERTY_NAME, Class.class);
return Gru.create(Micronaut.createLazy(() -> context.getBean(testClass), () -> context));
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -38,35 +38,53 @@
import java.util.function.Consumer;
import java.util.function.Supplier;

/**
* Client for Micronaut applications.
*
* This uses {@link Http} client to interact with {@link EmbeddedServer}.
*/
public class Micronaut implements Client {

/**
* {@link ApplicationContext} build helper.
*/
public static class MicronautApplicationBuilder {
private final Object unitTest;
private Consumer<ApplicationContextBuilder> contextBuilderConfiguration = b -> {};
private Consumer<ApplicationContext> contextConfiguration = b -> {};

public MicronautApplicationBuilder(Object unitTest) {
MicronautApplicationBuilder(Object unitTest) {
this.unitTest = unitTest;
}

/**
* Customize the application context.
* @param contextConfiguration application context configuration
* @return self
*/
public MicronautApplicationBuilder doWithContext(Consumer<ApplicationContext> contextConfiguration) {
this.contextConfiguration = this.contextConfiguration.andThen(contextConfiguration);
return this;
}


/**
* Customize the application context builder.
* @param contextBuilderConfiguration application context configuration
* @return self
*/
public MicronautApplicationBuilder doWithContextBuilder(Consumer<ApplicationContextBuilder> contextBuilderConfiguration) {
this.contextBuilderConfiguration = this.contextBuilderConfiguration.andThen(contextBuilderConfiguration);
return this;
}

/**
* Starts the internal {@link ApplicationContext} and returns the client instance.
* @return the new client instance
*/
public Client start() {
return start(false);
}

public Client start(boolean inject) {
SelfStartingContextProvider provider = new SelfStartingContextProvider(this);
if (inject) {
provider.getApplicationContext().inject(unitTest);
}
provider.getApplicationContext().inject(unitTest);
return create(unitTest, provider);
}
}
Expand All @@ -86,7 +104,7 @@ public ApplicationContext getApplicationContext() {
return context;
}

ApplicationContextBuilder builder = ApplicationContext.build();
ApplicationContextBuilder builder = ApplicationContext.builder();
micronautApplicationBuilder.contextBuilderConfiguration.accept(builder);

context = builder.build();
Expand All @@ -110,10 +128,23 @@ public void close() {
private final ApplicationContextProvider contextProvider;
private final Client delegate;

/**
* Starts building a client using a custom {@link ApplicationContext} for this test.
*
* @param unitTest the current test
* @return a builder for a client using a custom {@link ApplicationContext}
*/
public static MicronautApplicationBuilder build(Object unitTest) {
return new MicronautApplicationBuilder(unitTest);
}

/**
* Creates a new client either reusing the existing application context if the unit test
* implements {@link ApplicationContextProvider} or starting a new custom one.
*
* @param unitTest the current test
* @return a builder for a client using either existing or a custom {@link ApplicationContext}
*/
public static Client create(Object unitTest) {
if (unitTest instanceof ApplicationContextProvider) {
return new Micronaut((ApplicationContextProvider) unitTest, Http.create(unitTest));
Expand All @@ -122,10 +153,24 @@ public static Client create(Object unitTest) {
return build(unitTest).start();
}

/**
* Creates a lazy initialized client using the provided application context.
*
* @param unitTestProvider the current test provider
* @param provider the context provider
* @return a builder for a client using either existing or a custom {@link ApplicationContext}
*/
public static Client createLazy(Supplier<?> unitTestProvider, ApplicationContextProvider provider) {
return new Micronaut(provider, LazyClient.create(() -> Http.create(unitTestProvider.get())));
}

/**
* Creates a new client using the provided application context.
*
* @param unitTest the current test
* @param provider the context provider
* @return a builder for a client using either existing or a custom {@link ApplicationContext}
*/
public static Client create(Object unitTest, ApplicationContextProvider provider) {
return new Micronaut(provider, Http.create(unitTest));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,11 @@

public class MicronautGruExtensions {

/**
* Configures the {@link ApplicationContext}.
* @param configuration application context configuration
* @return self
*/
public static Micronaut.MicronautApplicationBuilder then(
Micronaut.MicronautApplicationBuilder self,
@DelegatesTo(value = ApplicationContext.class, strategy = Closure.DELEGATE_FIRST)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,11 @@

public class MicronautGruStaticExtensions {

/**
* Creates new client builder and configures the {@link ApplicationContextBuilder}.
* @param configuration application context builder configuration
* @return new custom application context builder
*/
@SuppressWarnings("unused")
public static Micronaut.MicronautApplicationBuilder build(
Micronaut self,
Expand Down

0 comments on commit fec332d

Please sign in to comment.