Generated from at 3.0.0 2020-08-11T17:36:18Z



Basic introduction (by example) to asserting the function behaviour.

While testing single lambda expression (usually very small peace of code), on its own, might be overkill. It might be beneficial in some cases to enclose tested solution into a functional interface and test its response (codomain) for the given input (domain).

For that purpose every functional interface from library has the assertion class (plus assertion classes for JRE function in any case they would be needed).

Before we use assertions

Attests and DefaultAttests are the classes that are aggregating all the factory methods you might need.


This is how some simple tests can be carried on based on functional assertions:

@Test public void example0() { String sut = "1234567890"; LBinaryOperator<String> replaceOperation = sut::replace; THEN.withinStringCodomain() // #1 .attestBinaryOp(replaceOperation) .inAllFollowingCases(result -> result.contains("_x_")) // #2 .doesApply("1", "_x_").asEqualTo("_x_234567890") // #3 .doesApply("2", "_x_").asEqualTo("1_x_34567890") .doesApply("3", "_x_").toEx(check -> check.must2Ex(Be::equalEx, "12_x_4567890")) // #4 .doesApply("3", null).withException(ex -> ex.isInstanceOf(NullPointerException.class)); }

At #1) We can manipulate AssertJ assertion for the codomain.

At #2) We can add recurring assertions (multiple if needed) to check generic assertions.

At #3) We can add as many corner cases as needed.

At #4) There is possibility to use fluent validations. The "ex" stands for "ex" variants of the methods that actually produce message.

Another example with some explanation below:

@Test(expectedExceptions = AssertionError.class, expectedExceptionsMessageRegExp = "Case \\(0\\) should evaluate with exception.") public void example() { THEN.attestFunc(function) .inAllFollowingCases(a -> a.isInstanceOf(Integer.class)) .doesApply(80).to(a -> a.isEqualTo(80)) .doesApply(81).toEqualTo(81) .doesApply(0).withException(e -> e.isExactlyInstanceOf(UnsupportedOperationException.class) .hasMessage("Some message")); }

What happens in above code is:

  • we check each time if the result is indeed an Integer (provided there were no exceptions),
  • we do two test calls to the function to check the result,
    • first of them operates on full ObjectAssert (and possibly checks more things).
    • second of them only checks if the return value is equal to specific value (we do not need to use lambda expression for that).
  • we also assert that for the argument value 0 there will be an exception

One unfortunate fact is that since this was a generic FunctionX<T,R,X> the assert we have each time is the ObjectAssert instance.

Specialised result assertions

We can always provide different base Assert for an generic type that is the result of the functions. By using withinCodomain() method:

@Test(expectedExceptions = AssertionError.class) public void assertThatInt() { THEN.withinCodomain(THEN::attestThatInt).attestFunc(function) .doesApply(80).to(a -> a.isGreaterThan(0)) // <- NOW WE CAN DO THIS .doesApply(81).toEqualTo(81) .doesApply(0).withException(e -> e.isExactlyInstanceOf(UnsupportedOperationException.class) .hasMessage("Some message")); }

Here are examples how you can specify specific AssertJ assertions for the generic codomain.

@Test public void assertThatIntAlternatives() { THEN.withinCodomain((LFunction<Integer, AbstractIntegerAssert>) Assertions::assertThat).attestFunc(function) .doesApply(80).to(a -> a.isGreaterThan(0)); THEN.withinCodomain(Assertions::assertThat, Integer.class, AbstractIntegerAssert.class).attestFunc(function) .doesApply(80).to(a -> a.isGreaterThan(0)); THEN.withinIntegerCodomain().attestFunc(function) .doesApply(80).to(a -> a.isGreaterThan(0)); }

### What if function do not have an input or output?

Every functional interface has its assertion class, that includes even LAction - LActionAssert In such cases where there is no domain and/or codomain, the assumption of the assertion class is that there might be some external influence or effect. Here is an example how to 'access' that external effect/influence:

@Test(expectedExceptions = AssertionError.class) public void testActionAssert() { THEN.attestAct(action) .doesExecute().when(() -> extInfluence.set(-99)).soThat(() -> assertThat(extEffect.get()).isEqualTo(-1)) .doesExecute().when(() -> extInfluence.set(0)).soThat(() -> assertThat(extEffect.get()).isEqualTo(-1)) .doesExecute().when(() -> extInfluence.set(1)).soThat(() -> assertThat(extEffect.get()).isEqualTo(1)) .doesExecute().when(() -> extInfluence.set(3)).soThat(() -> assertThat(extEffect.get()).isEqualTo(4000)); }

Generated from at 3.0.0 2020-08-11T17:36:18Z