Skip navigation links

Powerunit - Java Testing framework for JDK 1.8 0.1.1 API

This is the PowerUnit Framework : A test framework for Java 8+.

See: Description

Packages 
Package Description
ch.powerunit
Main functionnalities of powerunit.
ch.powerunit.exception
Contains all the exception.
ch.powerunit.helpers
Helpers capabilities
ch.powerunit.rules
Default implementation or abstract for rule.
ch.powerunit.surefire
Surefire integration
This is the PowerUnit Framework : A test framework for Java 8+.

Concepts

This framework provides a test framework for Java, based on the JDK 1.8. The idea are similar to the idea of the others test framework. First of all here are two simple examples.

Examples

The Hello world test example
import ch.powerunit.Test;
import ch.powerunit.TestSuite;

public class HelloWorldTest implements TestSuite {
  @Test()
  public void testHelloWorld1() {
    assertThat("Hello world").is(containsString(" "));
  }
 
}
Several elements are interesting here :
The Hello world with parameter test example
import java.util.Arrays;
import java.util.stream.Stream;

import ch.powerunit.Parameter;
import ch.powerunit.Parameters;
import ch.powerunit.Test;
import ch.powerunit.TestSuite;

public class HelloWorldParameterTest implements TestSuite {
  @Parameters("Input string is {0}, subString idx is {1}, expected result is {2}")
  public static Stream<Object[]> getDatas() {
    return Arrays.stream(new Object[][] { { "ab", 0, "ab" }, { "ab", 1, "b" } });
  }

  @Parameter(0)
  public String inputString;

  @Parameter(1)
  public int inputIndex;

  @Parameter(2)
  public String expectedString;

  @Test
  public void testSubString() {
    assertThat(inputString.substring(inputIndex)).is(expectedString);
  }
}
The interesting elements here are :

Tests action sequences order

Each test class is executed in isolation. The first action to be done is the instantiation of the class itself. Then the test execution can be :
  1. If the test use the @Parameters approach, the annotated method will be used to produce a list of input data. Each line of data will trigger the next step (injection at each run of the data into the field annotated @Parameter); If the @Parameters approach is not used, only one execution of the tests will be done.
  2. For each method annotated @Test, an execution will be done. This execution will be based on the passed @Rule, from the upper class to the lower class.
To demonstrate this sequence of action, here is an example of all theses concepts. Let's assume we have the two following classes :
import ch.powerunit.Rule;
import ch.powerunit.TestRule;
import ch.powerunit.TestSuite;
import ch.powerunit.rules.TestContextRule;

public abstract class ParentTest implements TestSuite {
  protected final TestContextRule context = new TestContextRule<>();

  @Rule
  public final TestRule level1 = context.around(before(this::prepare1).around(after(this::clean1)));

  public final void prepare1() {
    System.out.println(context.getTestContext().getFullTestName() + ":prepare1");
  }

  public final void clean1() {
    System.out.println(context.getTestContext().getFullTestName() + ":clean1");
  }
}

import java.util.Arrays;
import java.util.stream.Stream;

import ch.powerunit.Parameter;
import ch.powerunit.Parameters;
import ch.powerunit.Rule;
import ch.powerunit.Test;
import ch.powerunit.TestRule;

public class ChildrenTest extends ParentTest {

  @Parameters
  public static Stream<Object[]> getDatas() {
    return Arrays.stream(new Object[][] { { "A" }, { "B" } });
  }

  @Parameter(0)
  public String p1;

  @Rule
  public final TestRule level2 = before(this::prepare2).around(after(this::clean2));

  public final void prepare2() {
    System.out.println(context.getTestContext().getFullTestName() + ":prepare2");
  }

  public final void clean2() {
    System.out.println(context.getTestContext().getFullTestName() + ":clean2");
  }

  @Test
  public void test1() {
    System.out.println("test1 " + p1);
  }

  @Test
  public void test2() {
    System.out.println("test2 " + p1);
  }
}
The first class ParentTest defines a first level of rules, that will provide information on the test execution, one method to be executed before each test, and one method to be executed after each test. Then the second class ChildenTest extends the previous one and defines a second level of rules, with all to before and after method. In addition, each test will be executed twice, once with p1=A , once with p1=B . The output of the execution will be :
ch.powerunit.examples.ChildrenTest:test2[0]:prepare1
ch.powerunit.examples.ChildrenTest:test2[0]:prepare2
test2 A
ch.powerunit.examples.ChildrenTest:test2[0]:clean2
ch.powerunit.examples.ChildrenTest:test2[0]:clean1
ch.powerunit.examples.ChildrenTest:test1[0]:prepare1
ch.powerunit.examples.ChildrenTest:test1[0]:prepare2
test1 A
ch.powerunit.examples.ChildrenTest:test1[0]:clean2
ch.powerunit.examples.ChildrenTest:test1[0]:clean1
ch.powerunit.examples.ChildrenTest:test2[1]:prepare1
ch.powerunit.examples.ChildrenTest:test2[1]:prepare2
test2 B
ch.powerunit.examples.ChildrenTest:test2[1]:clean2
ch.powerunit.examples.ChildrenTest:test2[1]:clean1
ch.powerunit.examples.ChildrenTest:test1[1]:prepare1
ch.powerunit.examples.ChildrenTest:test1[1]:prepare2
test1 B
ch.powerunit.examples.ChildrenTest:test1[1]:clean2
ch.powerunit.examples.ChildrenTest:test1[1]:clean1
It is possible to say that the before of the parent class are executed before the once of the children class. The after are executed in the reverse order. Also, as the before/after action use the result of the TestContextRule , it also show that this rule is execute before all others. As parameters were used, the trace indicate that the sequence of rule action are used for each parameter set, and for each test.

In some specific case, it is possible that one rule required, to be builded, that another one is already executed. To do so, the around method also support receiving a Supplier parameter, that will be used, at the very last moment, to build the rule.

Assertion and Assumption usage

Assertion and assumption are provided by the interface TestSuite that may be implemented by the test class. Assertion and assumption use the same DSL language and capabilities, but they are started by a different methods : Several type of assertion/assumption are available : The provides matcher also support the new Optional concept of Java 8.

Annotations processor

PowerUnit provides an integration out of the box with the annotation processor of the java compiler. This is provided by the PowerUnitProcessor. The goal of this annotation processor is double :

Surefire integration

This test system can integrated out of the box with Surefire. This is done by adding this package as a dependencies of the surefire plugin :
<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-surefire-plugin</artifactId>
  <dependencies>
    <dependency>
      <groupId>ch.powerunit</groupId>
      <artifactId>powerunit</artifactId>
    </dependency>
  </dependencies>
</plugin>

About Hamcrest integration

Hamcrest is integrated with this framework, as a maven dependency. Here the TestSuite interface provides the standard hamcrest DSL features, with some additional matcher (for exception and the new Optional class for instance).
Skip navigation links

Copyright © 2014. All rights reserved.