https://github.com/openhft/chronicle-test-framework
https://github.com/openhft/chronicle-test-framework
Last synced: 5 months ago
JSON representation
- Host: GitHub
- URL: https://github.com/openhft/chronicle-test-framework
- Owner: OpenHFT
- License: apache-2.0
- Created: 2021-10-27T13:02:33.000Z (over 4 years ago)
- Default Branch: ea
- Last Pushed: 2024-04-12T08:36:45.000Z (about 2 years ago)
- Last Synced: 2024-04-12T15:34:00.360Z (about 2 years ago)
- Language: Java
- Size: 301 KB
- Stars: 23
- Watchers: 12
- Forks: 6
- Open Issues: 2
-
Metadata Files:
- Readme: README.adoc
- License: LICENSE
Awesome Lists containing this project
README
= Chronicle Test Framework
:css-signature: demo
:toc: macro
:toclevels: 2
:icons: font
image:https://maven-badges.herokuapp.com/maven-central/net.openhft/chronicle-test-framework/badge.svg[Maven Central,link=https://maven-badges.herokuapp.com/maven-central/net.openhft/chronicle-test-framework]
image:https://javadoc.io/badge2/net.openhft/chronicle-test-framework/javadoc.svg[Javadoc,link="https://www.javadoc.io/doc/net.openhft/chronicle-test-framework/latest/index.html"]
//image:https://javadoc-badge.appspot.com/net.openhft/chronicle-test-framework.svg?label=javadoc[JavaDoc, link=https://www.javadoc.io/doc/net.openhft/chronicle-test-framework]
image:https://img.shields.io/github/license/OpenHFT/Chronicle-Test-Framework[Licence]
image:https://img.shields.io/badge/release%20notes-subscribe-brightgreen[Release Notes,link="https://chronicle.software/release-notes/"]
image:https://sonarcloud.io/api/project_badges/measure?project=OpenHFT_ChronicleTestFramework&metric=alert_status[Quality Gate,link="https://sonarcloud.io/dashboard?id=OpenHFT_Chronicle-Test-Framework"]
toc::[]
== About
Chronicle Test Framework provides test-data generators and API metrics tools for JUnit 4 and JUnit 5. Use the combinators to create permutations, combinations and products, or analyse your packages with the metrics builder.
== Permutations
Permutations work like this:
[source,java]
----
@Test
void print() {
Permutation.of("A", "B", "C")
.forEach(System.out::println);
}
----
This will produce the following output:
[source,text]
----
[A, B, C]
[A, C, B]
[B, A, C]
[B, C, A]
[C, A, B]
[C, B, A]
----
Testing using permutations:
[source,java]
----
@TestFactory
// Exhaustively verifies that any order of setter invocation yields the same result
Stream demo() {
// Operations
final Consumer setA = myBean -> myBean.setA(1);
final Consumer setB = myBean -> myBean.setB(2);
final Consumer setC = myBean -> myBean.setC(3);
final MyBean expected = new MyBean(1, 2, 3);
// DynamicTests
return DynamicTest.stream(Permutation.of(setA, setB, setC),
Objects::toString,
operations -> {
final MyBean actual = new MyBean();
operations.forEach(oper -> oper.accept(actual));
assertEquals(expected, actual);
});
}
----
== API Metrics Builder
The API metrics feature analyses the public and internal surface of your packages.
Create the builder via `ApiMetrics.builder()` then supply the packages to scan, the metrics to apply and the accumulators that gather the results.
[source,java]
----
ApiMetrics metrics = ApiMetrics.builder()
.addStandardMetrics()
.addStandardAccumulators()
.addPackage("com.example")
.build();
----
The builder applies no defaults.
If you omit metrics or accumulators the result will be empty.
Default metrics and accumulators are only added when you call the relevant `addStandard` methods.
Packages with `.internal.` in the name, or those ending in `.internal`, are collected in a separate internal group.
== Combinations
Combinations work like this:
[source,java]
----
@Test
void print() {
Combination.of("A", "B", "C")
.forEach(System.out::println);
}
----
This will produce the following output:
[source,text]
----
[]
[A]
[B]
[C]
[A, B]
[A, C]
[B, C]
[A, B, C]
----
Testing using combinations:
[source,java]
----
@TestFactory // Try all combinations of cosmic ray interference for the Robot state machine
Stream demo() {
return DynamicTest.stream(Combination.>of(
FaultTolerantBitSet::cosmicRayBit3,
FaultTolerantBitSet::cosmicRayBit23,
FaultTolerantBitSet::cosmicRayBit13),
Objects::toString,
operations -> {
final FaultTolerantBitSet bitSet = new FaultTolerantBitSet();
operations.forEach(oper -> oper.accept(bitSet));
assertTrue(bitSet.isValid());
});
}
----
== Combinations and Permutations
Combinations and Permutations can be combined to create powerful exhaustive test vectors:
[source,java]
----
@Test
void demo() {
Combination.of("A", "B", "C")
.flatMap(Permutation::of)
.forEach(System.out::println);
}
----
This will produce the following output:
[source,text]
----
[]
[A]
[B]
[C]
[A, B]
[B, A]
[A, C]
[C, A]
[B, C]
[C, B]
[A, B, C]
[A, C, B]
[B, A, C]
[B, C, A]
[C, A, B]
[C, B, A]
----
== Products
Products are equivalent to nested loops but are easier to convert to a `Stream` of `DynamicTest` objects:
[source,java]
----
@Test
void print() {
Product.of(Arrays.asList("A", "B", "C"), Arrays.asList(1, 2, 3))
.forEach(System.out::println);
}
----
This will produce the following output:
[source,text]
----
Product2Impl{first=A, second=1}
Product2Impl{first=A, second=2}
Product2Impl{first=A, second=3}
Product2Impl{first=B, second=1}
Product2Impl{first=B, second=2}
Product2Impl{first=B, second=3}
Product2Impl{first=C, second=1}
Product2Impl{first=C, second=2}
Product2Impl{first=C, second=3}
----
Products can use built-in tuples like `Product2Impl` or we can provide custom constructors to use our own.
Testing using products:
[source,java]
----
@TestFactory
// Exhaustively tests if various empty collections invariants holds
Stream demo() {
// Operations
final List> collections = Arrays.asList(new LinkedList<>(), new ArrayList<>(), new HashSet<>());
// Operations
final Consumer> empty =
c -> assertTrue(c.isEmpty(), c.getClass() + ".empty() was false");
final Consumer> size =
c -> assertEquals(0, c.size(), c.getClass() + ".size() != 0");
final Consumer> streamCount =
c -> assertEquals(0, c.stream().count(), c.getClass() + ".stream().count() != 0");
final List>> operations = Arrays.asList(empty, size, streamCount);
// DynamicTests
return DynamicTest.stream(Product.of(collections, operations),
Objects::toString,
tuple -> {
tuple.second().accept(tuple.first());
});
}
----
== API Metrics Accumulators
The framework includes a small set of predefined accumulator suppliers used by the API metrics analysis.
They help to group metric counts in common ways.
* `perMethod()` groups by the full method signature so that overloaded methods are reported separately.
* `perClassAndMetric()` groups first by class and then by metric, giving a table of metric totals for each class.
* `PER_METRIC` provides totals for each metric across all classes.
* `PER_CLASS` totals all metrics for each class without distinction.
* `PER_PACKAGE` reports a single total for each package.
* `PER_METHOD_REFERENCE` groups by method name only, ignoring parameter types, so all overloads are counted as one.
The convenience factories in `Accumulator` expose the first two suppliers for general use.
The others are mainly for internal analyses but may be reused when custom behaviour is needed.