Knotx / knotx-junit5

JUnit 5 support and extensions for Vert.x projects
https://knotx.io
Apache License 2.0
0 stars 4 forks source link
integration-testing junit5 knotx

Build Status CodeFactor codecov Gradle Status

Knot.x JUnit5

JUnit 5 extensions and data type converters for Knot.x integration tests. Those tests allow to setup Knot.x instance with declared modules. It can be used both for module tests and regression tests.

Extensions

Provides following helpers:

KnotxExtension

Knot.x-specific extension that manages test Vert.x instances (with Knot.x configuration injection) and WireMock servers (through KnotxWiremockExtension).

Example usage:

@ExtendWith(KnotxExtension.class)
public class ExampleIntegrationTest {

  @ClasspathResourcesMockServer(port = 4001)
  protected WireMockServer mockRepository;

  @Test
  @KnotxApplyConfiguration({"default.conf", "overloaded.conf"})
  public void callModule_validKnotContextResult(VertxTestContext context, Vertx vertx) {
    // ...
  }
}

See more examples in ExampleKnotxJUnit5Test.

See Vert.x JUnit 5 integration for guide how to interact with VertxTestContext instances. Also, under io.knotx.junit5.util.RequestUtil there are some common methods that should make working with Vert.x tests contexts easier.

@KnotxApplyConfiguration

The annotation allows to specify one and more Knot.x configuration(s) to load for given test. It accepts a paths array and loads all configuration entries using Vert.x Config file stores, through a custom implementation enhanced with support for HOCON hierarchical configuration loading and cross-file variable references (for more details see KnotxConcatConfigProcessor reference). It supports two configuration semantics:

The order of the configuration files is important, as it defines the overloading order (base file first, overrides last). For conflicting (identical) keys in configuration, configuration entries arriving last will overwrite the value provided by the previous configuration files.

See Vert.x Config overloading rules for more details.

KnotxApplyConfiguration annotation can be placed on class, method, and parameter level. As such, configuration for parameter level will override method and class level, and method will override class level. For quick example see test package namespace io.knotx.junit5.example.

@RandomPort

If you want to randomize a port for using inside your test, you can define a namespace inside your HOCON config:

test {
  # random values generation section
  random {
    # all <name>.port entries will be substituted for different random ports
    globalServer.port = 12345
    actionAdapterService.port = 12345
  }
}

(example taken from example_random_config.conf file)

Then you can reference such variables from anywhere inside your configs; placeholder values will be substituted for real available port numbers:

@Test
@KnotxApplyConfiguration("config/example_random_config.conf")
public void injectRandomizedPort(@RandomPort Integer globalServerPort) {
  // integer parameter will be filled with generated port from section 'random' for entry 'globalServer'
}

The working example is defined in io.knotx.junit5.examples.ExampleKnotxJUnit5Test#injectRandomizedPort method from test classes.

KnotxWiremockExtension

Standalone WireMockServer injection and lifecycle management. Allows for:

Warning: if you use KnotxExtension, you must not inject KnotxWiremockExtension, as the functionality of the latter gets auto-imported into the former.

ClasspathResourcesMockServer injection and naming

WireMockServer instances are recognized by their identifier - either test class instance variable name or test method parameter name.

For example below, two servers will be available for testWiremockRunningOnPort method: mockServiceRandom with randomly assigned port, and server on port 3000.

@ExtendWith(KnotxWiremockExtension.class)
public class WireMockTest {

  private static final int MOCK_SERVICE_PORT_NUMBER = 3000;

  @ClasspathResourcesMockServer // will be started on a random port
  private WireMockServer mockServiceRandom;

  @Test
  public void testWiremockRunningOnPort(
      @ClasspathResourcesMockServer(port = MOCK_SERVICE_PORT_NUMBER) WireMockServer server)
      throws IOException, URISyntaxException {
    // ...
  }
}

One exception applies: one WireMockServer instance will be created per identifier within test given class:

@ExtendWith(KnotxWiremockExtension.class)
public class WireMockTest {

  @ClasspathResourcesMockServer
  private WireMockServer mockServiceRandom;

  @Test
  public void testWiremockEquality(
      @ClasspathResourcesMockServer WireMockServer mockServiceRandom) {
    assertTrue(this.mockServiceRandom == mockServiceRandom);
  }
}

Only one WireMockServer instance with random port is created (mockServiceRandom) and injected both into instance field and method parameter.

Referencing WireMockServer ports in Knot.x configuration

With KnotxExtension, created WireMockServer instances' ports will be available for referencing in Knot.x configuration under test.wiremock.<wiremockserver_identifier>.port variables (HOCON syntax only).

How to configure?

First we need to add Knot.x Junit5 to dependencies. We can get the module version from Knot.x Dependencies.

dependencies {
  implementation(platform("io.knotx:knotx-dependencies:${project.version}"))
  testImplementation(group = "io.knotx", name = "knotx-junit5")
  testImplementation(group = "io.vertx", name = "vertx-junit5")
}

The KnotxExtension and KnotxWiremockExtension use parameters names to correctly initialize injected fields and parameters (see @ClasspathResourcesMockServer). It requires to compile modules with

tasks.withType(JavaCompile) {
  options.compilerArgs << "-parameters"
}

Frequently asked questions

Is parallel test execution possible?

Currently not supported due to unknown Knot.x internal error that ends up in a segfault. However, all required functionality is implemented inside knotx-junit5 module.

Where can I find real examples how to use this extension?

Some simple examples are available in test package namespace io.knotx.junit5.example.
For other use cases see following Knot.x projects that use this Knot.x JUnit5 module:

Utils

HoconLoader

HoconLoader parses the HOCON configuration files and transforms all entries to JSON. This util is extremely helpful in Routing Handler's contract tests.

Bugs

All feature requests and bugs can be filed as issues on Gitub. Do not use Github issues to ask questions, post them on the User Group or Gitter Chat.

Licence

Knot.x modules are licensed under the Apache License, Version 2.0 (the "License")