JUnit (4 or 5) already provides some ways to parameterized tests and execute the same "test logic" against several data. However it is not that convenient to test multiple environments.
For instance, with Beam, you can desire to test against multiple runners your code and it requires to solve conflicts between runner dependencies, setup the correct classloaders etc…It is a lot of work!
To simplify such cases, the framework provides you a multi-environment support for your tests.
It is in the junit module and is usable with JUnit 4 and JUnit 5.
JUnit 4
@RunWith(MultiEnvironmentsRunner.class)
@Environment(Env1.class)
@Environment(Env1.class)
public class TheTest {
@Test
public void test1() {
// ...
}
}
The MultiEnvironmentsRunner
will execute the test(s) for each defined environments. It means it will
run test1
for Env1
and Env2
in previous example.
By default JUnit4
runner will be used to execute the tests in one environment but you can use @DelegateRunWith
to use another runner.
JUnit 5
JUnit 5 configuration is close to JUnit 4 one:
@Environment(EnvironmentsExtensionTest.E1.class)
@Environment(EnvironmentsExtensionTest.E2.class)
class TheTest {
@EnvironmentalTest
void test1() {
// ...
}
}
The main difference is you don’t use a runner (it doesn’t exist in JUnit 5) and you replace @Test
by @EnvironmentalTest
.
the main difference with JUnit 4 integration is that the tests are execute one after each other for all environments
instead of running all tests in each environments sequentially. It means, for instance, that @BeforeAll and @AfterAll are executed
once for all runners.
|
Provided environments
The provided environment setup the contextual classloader to load the related runner of Apache Beam.
Package: org.talend.sdk.component.junit.environment.builtin.beam
the configuration is read from system properties, environment variables, …. |
Class | Name | Description |
---|---|---|
ContextualEnvironment |
Contextual |
Contextual runner |
DirectRunnerEnvironment |
Direct |
Direct runner |
FlinkRunnerEnvironment |
Flink |
Flink runner |
SparkRunnerEnvironment |
Spark |
Spark runner |
Configuring environments
If the environment extends BaseEnvironmentProvider
and therefore defines an environment name - which is the case of the default ones, you can use EnvironmentConfiguration
to customize the system properties used for that environment:
@Environment(DirectRunnerEnvironment.class)
@EnvironmentConfiguration(
environment = "Direct",
systemProperties = @EnvironmentConfiguration.Property(key = "beamTestPipelineOptions", value = "..."))
@Environment(SparkRunnerEnvironment.class)
@EnvironmentConfiguration(
environment = "Spark",
systemProperties = @EnvironmentConfiguration.Property(key = "beamTestPipelineOptions", value = "..."))
@Environment(FlinkRunnerEnvironment.class)
@EnvironmentConfiguration(
environment = "Flink",
systemProperties = @EnvironmentConfiguration.Property(key = "beamTestPipelineOptions", value = "..."))
class MyBeamTest {
@EnvironmentalTest
void execute() {
// run some pipeline
}
}
if you set the system property <environment name>.skip=true then the environment related executions will be skipped.
|
Advanced usage
this usage assumes Beam 2.4.0 is in used and the classloader fix about the PipelineOptions is merged.
|
Dependencies:
<dependencies>
<dependency>
<groupId>org.talend.sdk.component</groupId>
<artifactId>component-runtime-junit</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jboss.shrinkwrap.resolver</groupId>
<artifactId>shrinkwrap-resolver-impl-maven</artifactId>
<version>3.0.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.talend.sdk.component</groupId>
<artifactId>component-runtime-beam</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.talend.sdk.component</groupId>
<artifactId>component-runtime-standalone</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
These dependencies brings into the test scope the JUnit testing toolkit, the Beam integration and the multi-environment testing toolkit for JUnit.
Then using the fluent DSL to define jobs - which assumes your job is linear and each step sends a single value (no multi-input/multi-output), you can write this kind of test:
@Environment(ContextualEnvironment.class)
@Environment(DirectRunnerEnvironment.class)
class TheComponentTest {
@EnvironmentalTest
void testWithStandaloneAndBeamEnvironments() {
from("myfamily://in?config=xxxx")
.to("myfamily://out")
.create()
.execute();
// add asserts on the output if needed
}
}
It will execute the chain twice:
-
with a standalone environment to simulate the studio
-
with a beam (direct runner) environment to ensure the portability of your job