test-as-you-think-core/src/main/java/testasyouthink/GivenWhenThenDsl.java
interface ThenWithoutResult<$SystemUnderTest> {

    AndThenWithoutResult<$SystemUnderTest> then(CheckedRunnable thenStep);

    AndThenWithoutResult<$SystemUnderTest> then(String expectationSpecification, CheckedRunnable thenStep);

    AndThenWithoutResult<$SystemUnderTest> then(CheckedConsumer<$SystemUnderTest> thenStep);

    AndThenWithoutResult<$SystemUnderTest> then(String expectationSpecification,
            CheckedConsumer<$SystemUnderTest> thenStep);

    AndThenWithoutResult<$SystemUnderTest> then(CheckedBooleanSupplier thenStep);

    AndThenWithoutResult<$SystemUnderTest> thenSutRepliesWithin(long timeLimit);

    AndThenWithoutResult<$SystemUnderTest> thenSutRepliesWithin(Duration durationLimit);

    void thenItSucceeds();

    AndThenWithoutResultStandardOutputCaptured<$SystemUnderTest> thenStandardOutput(
            CheckedConsumer<File> thenStep);

    AndThenWithoutResultStandardOutputCaptured<$SystemUnderTest> thenStandardOutput(
            String expectationSpecification, CheckedConsumer<File> thenStep);
}
test-as-you-think-core/src/main/java/testasyouthink/GivenWhenThenDsl.java
interface ThenFailure {

    AndThenFailure thenItFails();
}
test-as-you-think-core/src/main/java/testasyouthink/GivenWhenThenDsl.java
interface Then<$SystemUnderTest, $Result> {

    AndThen<$SystemUnderTest, $Result> then(CheckedConsumer<$Result> thenStep);

    AndThen<$SystemUnderTest, $Result> then(String expectationSpecification, CheckedConsumer<$Result> thenStep);

    AndThen<$SystemUnderTest, $Result> then(CheckedRunnable thenStep);

    AndThen<$SystemUnderTest, $Result> then(String expectationSpecification, CheckedRunnable thenStep);

    AndThen<$SystemUnderTest, $Result> then(CheckedPredicate<$Result> thenStep);

    AndThen<$SystemUnderTest, $Result> thenSutRepliesWithin(long timeLimit);

    AndThen<$SystemUnderTest, $Result> thenSutRepliesWithin(Duration durationLimit);

    void then(List<CheckedPredicate<$Result>> thenSteps);

    void then(CheckedConsumer<$Result> thenStepAboutResult,
            CheckedConsumer<$SystemUnderTest> thenStepAboutSystemUnderTest);

    void then(CheckedPredicate<$Result> thenStepAboutResult,
            CheckedPredicate<$SystemUnderTest> thenStepAboutSystemUnderTest);

    AndThenStandardOutputCaptured<$SystemUnderTest, $Result> thenStandardOutput(CheckedConsumer<File> thenStep);

    AndThenStandardOutputCaptured<$SystemUnderTest, $Result> thenStandardOutput(String expectationSpecification,
            CheckedConsumer<File> thenStep);
}
test-as-you-think-core/src/main/java/testasyouthink/function/CheckedBiConsumer.java
@FunctionalInterface
public interface CheckedBiConsumer<T, U> {

    void accept(T t, U u) throws Throwable;
}
test-as-you-think-core/src/main/java/testasyouthink/GivenWhenThenDsl.java
interface AndGivenArgument<$SystemUnderTest, $Argument> extends WhenApplyingOneArgument<$SystemUnderTest,
        $Argument> {

    <$Argument2> AndGivenTwoArguments<$SystemUnderTest, $Argument, $Argument2> andArgument(
            CheckedSupplier<$Argument2> givenStep);

    <$Argument2> AndGivenTwoArguments<$SystemUnderTest, $Argument, $Argument2> andArgument(
            Class<$Argument2> mutableArgumentClass, CheckedConsumer<$Argument2> givenStep);

    <$Argument2> AndGivenTwoArguments<$SystemUnderTest, $Argument, $Argument2> andArgument(String description,
            CheckedSupplier<$Argument2> givenStep);

    <$Argument2> AndGivenTwoArguments<$SystemUnderTest, $Argument, $Argument2> andArgument(String description,
            $Argument2 argument);
}
test-as-you-think-core/src/main/java/testasyouthink/function/CheckedSupplier.java
public interface CheckedSupplier<R> {

    R get() throws Throwable;
}
test-as-you-think-core/src/main/java/testasyouthink/function/CheckedConsumer.java
@FunctionalInterface
public interface CheckedConsumer<T> {

    void accept(T t) throws Throwable;
}
test-as-you-think-core/src/main/java/testasyouthink/preparation/Preparation.java
public class Preparation<$SystemUnderTest> {

    private final Functions functions = Functions.INSTANCE;
    private final SutPreparation sutPreparation = SutPreparation.INSTANCE;
    private final ArgumentPreparation argumentPreparation = ArgumentPreparation.INSTANCE;
    private final Queue<Consumer<$SystemUnderTest>> givenSteps;
    private Supplier<$SystemUnderTest> givenSutStep;
    private Queue<Supplier> argumentSuppliers;
    private $SystemUnderTest systemUnderTest;
    private boolean stdoutCaptured;

    public Preparation() {
        givenSteps = new ArrayDeque<>();
        argumentSuppliers = new LinkedList<>();
        stdoutCaptured = false;
    }

    public Preparation(Class<$SystemUnderTest> sutClass) {
        this();
        givenSutStep = sutPreparation.buildSutSupplier(sutClass);
    }

    public Preparation($SystemUnderTest systemUnderTest) {
        this();
        givenSutStep = sutPreparation.buildSutSupplier(systemUnderTest);
    }

    public Preparation(CheckedSupplier<$SystemUnderTest> givenSutStep) {
        this();
        this.givenSutStep = sutPreparation.buildSutSupplier(givenSutStep);
    }

    public void recordGivenStep(CheckedRunnable givenStep) {
        givenSteps.add(functions.toConsumer(() -> {
            try {
                givenStep.run();
            } catch (Throwable throwable) {
                throw new PreparationError("Fails to prepare the test fixture!", throwable);
            }
        }));
    }

    public void recordGivenStep(CheckedConsumer<$SystemUnderTest> givenStep) {
        givenSteps.add(sutPreparation.buildSutSupplier(givenStep));
    }

    public <$Argument> void recordGivenStep(CheckedSupplier<$Argument> givenStep) {
        argumentSuppliers.add(argumentPreparation.buidArgumentSupplier(givenStep));
    }

    public <$Argument> void recordGivenStep(Class<$Argument> mutableArgumentClass,
            CheckedConsumer<$Argument> givenStep) {
        argumentSuppliers.add(argumentPreparation.buildMutableArgumentSupplier(mutableArgumentClass, givenStep));
    }

    public Queue<Supplier> getArgumentSuppliers() {
        return argumentSuppliers;
    }

    public void prepareFixtures() {
        $SystemUnderTest sutToPrepareAtFirst = systemUnderTest();
        while (!givenSteps.isEmpty()) {
            givenSteps
                    .poll()
                    .accept(sutToPrepareAtFirst);
        }
    }

    public void prepareFixturesSeparately() {
        prepareFixtures();
        argumentSuppliers.forEach(Supplier::get);
    }

    private $SystemUnderTest systemUnderTest() {
        if (systemUnderTest == null && givenSutStep != null) {
            systemUnderTest = givenSutStep.get();
        }
        return systemUnderTest;
    }

    public Supplier<$SystemUnderTest> supplySut() {
        return this::systemUnderTest;
    }

    public void captureStdout() {
        if (!stdoutCaptured) {
            recordGivenStep(() -> {
                Path stdoutPath = Files.createTempFile("actual_result", ".txt");
                stdoutPath
                        .toFile()
                        .deleteOnExit();
                StandardRedirection.STDOUT_PATHS.put(currentThread().getId(), stdoutPath);
                StandardRedirection.STREAMS_TO_FILE.put(currentThread().getId(),
                        new PrintStream(stdoutPath.toString()));
            });

            stdoutCaptured = true;
        }
    }

    public Path getStdoutPath() {
        return StandardRedirection.STDOUT_PATHS.get(currentThread().getId());
    }

    private static class StandardRedirection {

        private static final Map<Long, Path> STDOUT_PATHS;
        private static final Map<Long, PrintStream> STREAMS_TO_FILE;
        private static final PrintStream SYSTEM_OUT;
        private static final PrintStream SYSTEM_ERR;

        static {
            SYSTEM_OUT = System.out;
            SYSTEM_ERR = System.err;
            STDOUT_PATHS = new HashMap<>();
            STREAMS_TO_FILE = new HashMap<>();

            commuteStandardOutputs();
        }

        private static void commuteStandardOutputs() {
            redirectStreamOnce(SYSTEM_OUT, System::setOut);
            redirectStreamOnce(SYSTEM_ERR, System::setErr);
        }

        private static void redirectStreamOnce(final PrintStream printStream, Consumer<PrintStream> redirectTo) {
            PrintStream allInOne = new PrintStream(new OutputStream() {
                @Override
                public void write(int b) throws IOException {
                    printStream.write(b);
                    if (!STREAMS_TO_FILE.isEmpty()) {
                        STREAMS_TO_FILE
                                .get(currentThread().getId())
                                .write(b);
                    }
                }
            });
            redirectTo.accept(allInOne);
        }
    }
}
test-as-you-think-core/src/main/java/testasyouthink/GivenWhenThenDsl.java
interface AndGivenTwoArguments<$SystemUnderTest, $Argument1, $Argument2> extends
        WhenApplyingTwoArguments<$SystemUnderTest, $Argument1, $Argument2> {

    <$Argument3> WhenApplyingThreeArguments<$SystemUnderTest, $Argument1, $Argument2, $Argument3> andArgument(
            CheckedSupplier<$Argument3> givenStep);

    <$Argument3> WhenApplyingThreeArguments<$SystemUnderTest, $Argument1, $Argument2, $Argument3> andArgument(
            Class<$Argument3> mutableArgumentClass, CheckedConsumer<$Argument3> givenStep);

    <$Argument3> WhenApplyingThreeArguments<$SystemUnderTest, $Argument1, $Argument2, $Argument3> andArgument(
            String description, CheckedSupplier<$Argument3> givenStep);

    <$Argument3> WhenApplyingThreeArguments<$SystemUnderTest, $Argument1, $Argument2, $Argument3> andArgument(
            String description, $Argument3 argument);
}
test-as-you-think-core/src/main/java/testasyouthink/function/Functions.java
public enum Functions {

    INSTANCE;

    public <T> Consumer<T> toConsumer(Runnable runnable) {
        return toBeConsumed -> runnable.run();
    }

    public CheckedConsumer<Void> toCheckedConsumer(CheckedRunnable runnable) {
        return toBeConsumed -> runnable.run();
    }

    public <T, R> CheckedFunction<T, R> toFunction(CheckedConsumer<T> checkedConsumer) {
        return toBeConsumed -> {
            checkedConsumer.accept(toBeConsumed);
            return null;
        };
    }

    public <R> CheckedFunction<Void, R> toCheckedFunction(CheckedSupplier<R> supplier) {
        return Void -> supplier.get();
    }

    public <R> CheckedFunction<Void, R[]> toCheckedFunction(CheckedArraySupplier<R> supplier) {
        return Void -> supplier.get();
    }

    public <T> CheckedFunction<T, Throwable> toFunctionWithThrowableAsResult(CheckedConsumer<T> checkedConsumer) {
        return toBeConsumed -> {
            Throwable result = null;
            try {
                checkedConsumer.accept(toBeConsumed);
            } catch (Throwable thrown) {
                result = thrown;
            }
            return result;
        };
    }

    public CheckedFunction<Void, Throwable> toFunctionWithThrowableAsResult(CheckedRunnable whenStep) {
        return Void -> {
            try {
                whenStep.run();
            } catch (Throwable thrown) {
                return thrown;
            }
            return null;
        };
    }

    public <$Value> CheckedSupplier<$Value> toCheckedSupplier($Value value) {
        return () -> value;
    }

    public <$Target, $Argument, $Result> CheckedFunction<$Target, $Result> toFunction(
            CheckedBiFunction<$Target, $Argument, $Result> biFunction, Queue<Supplier> arguments) {
        return target -> biFunction.apply(target, ($Argument) arguments
                .remove()
                .get());
    }

    public <$Target, $Argument1, $Argument2, $Result> CheckedFunction<$Target, $Result> toFunction(
            CheckedTriFunction<$Target, $Argument1, $Argument2, $Result> triFunction, Queue<Supplier> arguments) {
        return toFunction(toBiFunction(triFunction, arguments), arguments);
    }

    public <$Target, $Argument1, $Argument2, $Argument3, $Result> CheckedFunction<$Target, $Result> toFunction(
            CheckedQuadriFunction<$Target, $Argument1, $Argument2, $Argument3, $Result> quadriFunction,
            Queue<Supplier> arguments) {
        return toFunction(toBiFunction(toTriFunction(quadriFunction, arguments), arguments), arguments);
    }

    public <$Target, $Argument> CheckedConsumer<$Target> toConsumer(CheckedBiConsumer<$Target, $Argument> biConsumer,
            Queue<Supplier> arguments) {
        return target -> biConsumer.accept(target, ($Argument) arguments
                .remove()
                .get());
    }

    public <$Target, $Argument1, $Argument2> CheckedConsumer<$Target> toConsumer(
            CheckedTriConsumer<$Target, $Argument1, $Argument2> triConsumer, Queue<Supplier> arguments) {
        return toConsumer(toBiConsumer(triConsumer, arguments), arguments);
    }

    public <$Target, $Argument1, $Argument2, $Argument3> CheckedConsumer<$Target> toConsumer(
            CheckedQuadriConsumer<$Target, $Argument1, $Argument2, $Argument3> quadriConsumer,
            Queue<Supplier> arguments) {
        return toConsumer(toBiConsumer(toTriConsumer(quadriConsumer, arguments), arguments), arguments);
    }

    static class ConsumerUnitTransformation {

        static <$Target, $Argument1, $Argument2> CheckedBiConsumer<$Target, $Argument1> toBiConsumer(
                CheckedTriConsumer<$Target, $Argument1, $Argument2> triConsumer, Queue<Supplier> arguments) {
            return (target, argument1) -> triConsumer.accept(target, argument1, ($Argument2) arguments
                    .remove()
                    .get());
        }

        static <$Target, $Argument1, $Argument2, $Argument3> CheckedTriConsumer<$Target, $Argument1, $Argument2>
        toTriConsumer(
                CheckedQuadriConsumer<$Target, $Argument1, $Argument2, $Argument3> quadriConsumer,
                Queue<Supplier> arguments) {
            return (target, argument1, argument2) -> quadriConsumer.accept(target, argument1, argument2,
                    ($Argument3) arguments
                            .remove()
                            .get());
        }
    }

    static class FunctionUnitTransformation {

        static <$Target, $Argument1, $Argument2, $Result> CheckedBiFunction<$Target, $Argument1, $Result> toBiFunction(
                CheckedTriFunction<$Target, $Argument1, $Argument2, $Result> triFunction, Queue<Supplier> arguments) {
            return (target, argument1) -> triFunction.apply(target, argument1, ($Argument2) arguments
                    .remove()
                    .get());
        }

        static <$Target, $Argument1, $Argument2, $Argument3, $Result> CheckedTriFunction<$Target, $Argument1,
                $Argument2, $Result> toTriFunction(
                CheckedQuadriFunction<$Target, $Argument1, $Argument2, $Argument3, $Result> quadriFunction,
                Queue<Supplier> arguments) {
            return (target, argument1, argument2) -> quadriFunction.apply(target, argument1, argument2,
                    ($Argument3) arguments
                            .remove()
                            .get());
        }
    }
}
test-as-you-think-core/src/main/java/testasyouthink/function/CheckedBiFunction.java
@FunctionalInterface
public interface CheckedBiFunction<T, U, R> {

    R apply(T t, U u) throws Throwable;
}


Question: import testasyouthink.function.CheckedSupplier;
import testasyouthink.function.Functions;
import testasyouthink.preparation.Preparation;
import testasyouthink.GivenWhenThenDsl.PreparationStage.AndGivenArgument;
import testasyouthink.GivenWhenThenDsl.PreparationStage.AndGivenTwoArguments;
import testasyouthink.GivenWhenThenDsl.VerificationStage.Then;
import testasyouthink.GivenWhenThenDsl.VerificationStage.ThenFailure;
import testasyouthink.GivenWhenThenDsl.VerificationStage.ThenWithoutResult;
import testasyouthink.function.CheckedBiConsumer;
import testasyouthink.function.CheckedBiFunction;
import testasyouthink.function.CheckedConsumer;
/*-
 * #%L
 * Test As You Think
 * %%
 * Copyright (C) 2017 - 2018 Xavier Pigeon and TestAsYouThink contributors
 * %%
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Lesser Public License for more details.
 * 
 * You should have received a copy of the GNU General Lesser Public
 * License along with this program.  If not, see
 * <http://www.gnu.org/licenses/lgpl-3.0.html>.
 * #L%
 */

package testasyouthink;


public class GivenArgumentWhenSteps<$SystemUnderTest, $Argument> implements AndGivenArgument<$SystemUnderTest,
        $Argument> {

    private final Functions functions = Functions.INSTANCE;
    private final Preparation<$SystemUnderTest> preparation;
    private final ThenStepFactory thenStepFactory = ThenStepFactory.INSTANCE;

    GivenArgumentWhenSteps(Preparation<$SystemUnderTest> preparation) {this.preparation = preparation;}

    @Override
    public <$Argument2> AndGivenTwoArguments<$SystemUnderTest, $Argument, $Argument2> andArgument(
            CheckedSupplier<$Argument2> givenStep) {
        preparation.recordGivenStep(givenStep);
        return new GivenTwoArgumentsWhenSteps<>(preparation);
    }

    @Override
    public <$Argument2> AndGivenTwoArguments<$SystemUnderTest, $Argument, $Argument2> andArgument(
            Class<$Argument2> mutableArgumentClass, CheckedConsumer<$Argument2> givenStep) {
        preparation.recordGivenStep(mutableArgumentClass, givenStep);
        return new GivenTwoArgumentsWhenSteps<>(preparation);
    }

    @Override
    public <$Argument2> AndGivenTwoArguments<$SystemUnderTest, $Argument, $Argument2> andArgument(String description,
            CheckedSupplier<$Argument2> givenStep) {
        return andArgument(givenStep);
    }

    @Override
    public <$Argument2> AndGivenTwoArguments<$SystemUnderTest, $Argument, $Argument2> andArgument(String description,
            $Argument2 argument) {
        preparation.recordGivenStep(functions.toCheckedSupplier(argument));
        return new GivenTwoArgumentsWhenSteps<>(preparation);
    }

    @Override
Answer:     public ThenWithoutResult<$SystemUnderTest> when(CheckedBiConsumer<$SystemUnderTest, $Argument> whenStep) {