diff --git a/.gitignore b/.gitignore index 97d92ed..5a88f2f 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,7 @@ build/ dist/ out/ target/ +*.versionsBackup ###################### # OS generated files # @@ -22,6 +23,7 @@ thumbs.db .settings/ .idea/ *.iml +*.sw* ####### # SCM # diff --git a/README.md b/README.md index 7e0e2b8..d7ff5c9 100644 --- a/README.md +++ b/README.md @@ -33,6 +33,7 @@ Please use this [permalink](https://goo.gl/XqS4Zf) (goo.gl/XqS4Zf) to share this + [Failures](#failures) - [Expected failures](#expected-failures) - [Unexpected failures](#unexpected-failures) + - [No failure](#no-failure) + [Time limit](#time-limit) + [Fluent assertions as a chained extension](#fluent-assertions-as-a-chained-extension) - [Functional approach of testing](#functional-approach-of-testing) @@ -40,6 +41,7 @@ Please use this [permalink](https://goo.gl/XqS4Zf) (goo.gl/XqS4Zf) to share this - [Releases](#releases) * [Versioning](#versioning) * [Release Notes](#release-notes) + + [0.7 version: All testing steps as stage by stage checked functions](#07-version-all-testing-steps-as-stage-by-stage-checked-functions) + [0.6 version: Fluent assertions as if you meant AssertJ](#06-version-fluent-assertions-as-if-you-meant-assertj) + [0.5 version: System under test as a test fixture](#05-version-system-under-test-as-a-test-fixture) + [0.4.2 version: Cobertura as a code coverage analyzer](#042-version-cobertura-as-a-code-coverage-analyzer) @@ -56,9 +58,9 @@ Please use this [permalink](https://goo.gl/XqS4Zf) (goo.gl/XqS4Zf) to share this *TestAsYouThink* is an open source software library in Java for testing purposes. It is designed as a **fluent API** that will change the way development teams write their unit and integration tests. It aims to take control over the coding practices as **executable guidelines**, from beginners to experts, to get **high-quality tests**. Why should you adopt *TestAsYouThink*? - It promotes good coding practices for testing, on writing tests rather than before it with training or after it with code reviews. -- It makes the testing language ubiquitous to give a better structure based on compilable code rather than textual comments to the test code. +- It makes the testing language [ubiquitous](https://martinfowler.com/bliki/UbiquitousLanguage.html) to give a better structure based on compilable code rather than textual comments to the test code. - It improves test code readability and may bring more conciseness. -- It brings a functional programming approach to testing that makes reusing test code easier and more natural. +- It brings a [functional programming](https://en.wikipedia.org/wiki/Functional_programming) approach to testing that makes reusing test code easier and more natural. - It is designed to be easy to use thanks to code completion. - It builds new original features to test execution from version to version. @@ -77,7 +79,7 @@ Add *TestAsYouThink* as a dependency to your project with [Maven](https://maven. com.github.xapn test-as-you-think-core - 0.6 + 0.7 ``` @@ -123,7 +125,7 @@ Of course, it is also possible to test any void method, instead of a non-void on import static testasyouthink.TestAsYouThink.givenSut; ... -givenSut(systemUnderTest) +givenSut(SystemUnderTest::new) .given(() -> { // Preparation of fixtures }).when(sut -> { @@ -233,8 +235,8 @@ Notice that the `whatIsSpecial` name must specify the argument and it replaces t You can use different syntaxes to pass the event to the `when()` method: - a method reference (`SystemUnderTest::targetMethod` or `systemUnderTest::targetMethod` where `systemUnderTest` is an instance), -- a statement lambda (`sut -> { return sut.targetMethod(); }`), -- an expression lambda (`sut -> sut.targetMethod()`). +- a lambda statement (`sut -> { return sut.targetMethod(); }`), +- a lambda expression (`sut -> sut.targetMethod()`). All of them are useful: the more proper one depends on the use case. @@ -245,6 +247,7 @@ You can favor the simplest `when()` method, or choose a more explicit, alternate To write very simple tests, you might want to directly attack the system under test. In such a use case, the API syntax becomes very minimalist. ```java import static testasyouthink.TestAsYouThink.when; +import static testasyouthink.TestAsYouThink.resultOf; ... when(() -> systemUnderTest.targetMethod(oneOrMoreArguments)).then(...); // or... @@ -255,13 +258,13 @@ resultOf(SystemUnderTest::targetMethod).satisfies(requirements); // to chain flu ### Avoid ambiguous method calls -To define the event, you may want to pass an expression lambda to the `when()` method like this. +To define the event, you may want to pass a lambda expression to the `when()` method like this. ```java givenSutClass(SystemUnderTest.class) .when(sut -> sut.testedMethod()) // compilation error .then(...); ``` -In such a case, the compiler meets an error because of an ambiguous method call: it does not know which `when()` method must be called. One receives a lambda that returns a value, while another one receives a lambda that returns nothing. Instead of casting the expression lambda to a function or a consumer, you can avoid this compilation problem by using the following alternate methods. +In such a case, the compiler meets an error because of an ambiguous method call: it does not know which `when()` method must be called. One receives a lambda that returns a value, while another one receives a lambda that returns nothing. Instead of casting the lambda expression to a function or a consumer or replacing it with a lambda statement, you can solve this compilation problem by using the following alternate methods. Without return: ```java @@ -302,7 +305,7 @@ givenSutClass(SystemUnderTest.class).when(sut -> { return sut.nonVoidMethod(); } ### Specifying expectations -You are encouraged to explain the system under test behavior by specifying your expectations. What is the expected behavior in the current situtation? +You are encouraged to explain the system under test behavior by specifying your expectations. What is the expected behavior in the current situation? ```java givenSutClass(SystemUnderTest.class).when(sut -> { ... }) .then("first specified expectation", result -> { @@ -343,7 +346,10 @@ givenSutClass(SystemUnderTest.class) Without an explicit SUT, you get: ```java -whenOutsideOperatingCondtions(() -> { +import static testasyouthink.TestAsYouThink.whenOutsideOperatingConditions; +... + +whenOutsideOperatingConditions(() -> { // where an event causes a failure }) .thenItFails(); @@ -353,15 +359,24 @@ You can also verify the cause like follows: `thenItFails().havingCause(ExpectedC #### Unexpected failures -When an unexpected failure occurs - because of a regression for example -, the test fails by raising an `Error`, because the defaut behavior consists of assuming no failure should happen, unless the software developer wants. There is one `Error` type per testing stage as indicated in the table below. +When an unexpected failure occurs - because of a regression for example -, the test fails by raising an `Error`, because the defaut behavior consists of assuming no failure should happen, unless the software developer wants. Each `Error` type belongs to one testing stage as indicated in the table below. -Testing stage | Error type -------------- | ---------- -Preparation | `PreparationError` -Execution | `ExecutionError` -Verification | `AssertionError` +Testing stage | Error type | Meaning +------------- | ------------------- | ------- +Preparation | `PreparationError` | A failure happened while trying to prepare the test fixture. The test is not ready for execution. +Execution | `ExecutionError` | The target method failed to execute. Either the system under test is not ready for execution and some source code is missing, or the preparation is uncomplete. +Verification | `VerificationError` | A failure prevented the verification stage from achieving the whole set of assertions. +Verification | `AssertionError` | The behavior during the execution was not compliant with the expectations. Either it is a regression and the SUT must be fixed, or the test needs to be updated after a behavioral change of the SUT. -When a test fails, the origin of the raised error becomes the error cause and the stack trace should explain what exactly happened: the first failure points out the testing stage so that you know what kind of error it is, and the second one is the real failure cause. +When a test fails, the origin of the raised error becomes the error cause and the stack trace should explain what exactly happened: the first failure points out the testing stage so that you know what kind of solution is needed, and the second one is the real failure cause. + +#### No failure + +Sometimes the only thing to verify when executing the target method is that no failure happens. This kind of assertion is useful for the methods whose the only purpose is to check a requirement and to raise an exception if it is not satisfied. +```java +givenSut(SystemUnderClass::new).when(SystemUnderTest::targetMethod) +.thenItSucceeds(); +``` ### Time limit @@ -387,6 +402,9 @@ The advantage of *TestAsYouThink* is that the time limit is only applied to the You never write your assertions without adding [AssertJ](http://joel-costigliola.github.io/assertj) to your projects, don't you? If you have written your test on starting by the event, like this for example... ```java +import static org.assertj.core.api.Assertions.assertThat; +... + when(SystemUnderTest::targetMethod) .then(fellowshipOfTheRing -> assertThat(fellowshipOfTheRing) @@ -410,19 +428,24 @@ This usage is foreseen for very simple tests only. On the contrary, if a test sc Why use `resultOf()` rather than `assertThat()`? Here the goal is to identify the actual result against the expected result at a glance. According to the assertion API, whether it be [JUnit](http://junit.org/junit5/docs/current/api/org/junit/jupiter/api/Assertions.html) or be [AssertJ](http://joel-costigliola.github.io/assertj/core-8/api/org/assertj/core/api/Assertions.html) or be anything else, the order between the actual and expected results is never the same. ```java +/* Java only */ assert expectedOrActual.equals(actualOrExpected); // expected or actual at first with the Java assert keyword +/* JUnit */ org.junit.Assert.assertEquals(expected, actual); // expected at first with JUnit 4 org.junit.jupiter.api.Assertions.assertEquals(expected, actual); // expected at first with JUnit 5 org.testng.AssertJUnit.assertEquals(expected, actual); // expected at first with TestNG +/* Hamcrest */ +org.hamcrest.MatcherAssert.assertThat(actual, org.hamcrest.Matchers.is(expected)); // actual at first with Hamcrest +/* AssertJ */ org.assertj.core.api.Assertions.assertThat(actual).isEqualTo(expected); // actual at first with AssertJ ``` -As a consequence, if both are inverted, the error message will be wrong and will mislead developers before fixing a failing test. The *TestAsYouThink* `resultOf()` leaves no doubt about which is what by making the testing language ubiquitous. +As a consequence, if both are inverted, the error message will be wrong and will mislead developers before fixing a failing test. The *TestAsYouThink* `resultOf()` leaves no doubt about which is what by making the testing language [ubiquitous](https://martinfowler.com/bliki/UbiquitousLanguage.html). # Functional approach of testing -The functional programming approach of *TestAsYouThink* applied to testing is a very important advantage for software developers. As the API is designed to receive the test steps as functions, it makes you free to factorize many little pieces of code and to assembly them again as new test scenarii. Whereas the granularity of reuse of most of testing frameworks is based on classes, you will take advantage of the ability of *TestAsYouThink* to play with more and more bricks of code to expand the covered business cases. +The [functional programming](https://en.wikipedia.org/wiki/Functional_programming) approach of *TestAsYouThink* applied to testing is a very important advantage for software developers. As the API is designed to receive the test steps as functions, it makes you free to factorize many little pieces of code and to assembly them again as new test scenarii. Whereas the granularity of reuse of most of testing frameworks is based on classes, you will take advantage of the ability of *TestAsYouThink* to play with more and more bricks of code to expand the covered business cases. -You are even able to begin to code a new component behavior directly in a statement lambda as a *When* step inside a test method. If you are already a [Test-Driven Development](https://en.wikipedia.org/wiki/Test-driven_development) aficionado, be aware it might be a second stage on the [TDD](https://en.wikipedia.org/wiki/Test-driven_development) road to improve and expand your practices. Make the test pass by writing the least implementation code you can in the test method comes from [TDD as if you meant it](https://cumulative-hypotheses.org/2011/08/30/tdd-as-if-you-meant-it). +You are even able to begin to code a new component behavior directly in a lambda statement as a *When* step inside a test method. If you are already a [Test-Driven Development](https://en.wikipedia.org/wiki/Test-driven_development) aficionado, be aware it might be a second stage on the [TDD](https://en.wikipedia.org/wiki/Test-driven_development) road to improve and expand your practices. Make the test pass by writing the least implementation code you can in the test method comes from [TDD as if you meant it](https://cumulative-hypotheses.org/2011/08/30/tdd-as-if-you-meant-it). > *TestAsYouThink* is the first and only testing API that naturally supports the "TDD as if you meant it" practice. # Code Examples @@ -439,6 +462,19 @@ To understand how version numbers change, please read the [Semantic Versioning]( ## Release Notes +### 0.7 version: All testing steps as stage by stage checked functions + +- Improve the execution stage within a time limit and its corresponding assertions. + - Prepare the SUT separately, and other usual test fixtures. + - Prepare the arguments of the target method separately. +- Check the not yet checked testing steps. + - Check the preparation steps of the system under test. + - Check the preparation steps of the arguments of the target method. + - Check the execution steps. + - Check the verification steps. +- Verify no failure happens. +- Verify both the result and SUT expectations. + ### 0.6 version: Fluent assertions as if you meant AssertJ - Use the [AssertJ](http://joel-costigliola.github.io/assertj) assertions like an extension of the *TestAsYouThink* API with its `resultOf()` end point. @@ -463,7 +499,7 @@ To understand how version numbers change, please read the [Semantic Versioning]( ### 0.4 version: Time limit as an expectation - Expect that the system under test replies within a time limit. -- Resolve ambiguous method calls in relation to using expression lambdas. +- Resolve ambiguous method calls in relation to using lambda expressions. - Start to write a test with the when step. ### 0.3 version: TestAsYouThink as a Maven distributed OSS library diff --git a/assets/images/TestAsYouThink.png b/assets/images/TestAsYouThink.png index 5785194..781b9a4 100755 Binary files a/assets/images/TestAsYouThink.png and b/assets/images/TestAsYouThink.png differ diff --git a/pom.xml b/pom.xml index 3e47bf6..527dc01 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.github.xapn test-as-you-think-project - 0.6 + 0.7 pom TestAsYouThink Project The TestAsYouThink project aims to provide tooling to improve test code quality and to make testing @@ -448,14 +448,14 @@ org.easymock easymock - 3.4 + 3.5 test org.mockito mockito-core - 2.8.47 + 2.10.0 test diff --git a/test-as-you-think-core/pom.xml b/test-as-you-think-core/pom.xml index 6171920..04b357a 100644 --- a/test-as-you-think-core/pom.xml +++ b/test-as-you-think-core/pom.xml @@ -5,7 +5,7 @@ com.github.xapn test-as-you-think-project - 0.6 + 0.7 test-as-you-think-core diff --git a/test-as-you-think-core/src/main/java/testasyouthink/GivenArgumentWhenSteps.java b/test-as-you-think-core/src/main/java/testasyouthink/GivenArgumentWhenSteps.java index 7f181cf..e904457 100644 --- a/test-as-you-think-core/src/main/java/testasyouthink/GivenArgumentWhenSteps.java +++ b/test-as-you-think-core/src/main/java/testasyouthink/GivenArgumentWhenSteps.java @@ -29,12 +29,11 @@ import testasyouthink.GivenWhenThenDsl.VerificationStage.ThenWithoutResult; import testasyouthink.function.CheckedBiConsumer; import testasyouthink.function.CheckedBiFunction; +import testasyouthink.function.CheckedConsumer; import testasyouthink.function.CheckedSupplier; import testasyouthink.function.Functions; import testasyouthink.preparation.Preparation; -import java.util.function.Consumer; - public class GivenArgumentWhenSteps<$SystemUnderTest, $Argument> implements AndGivenArgument<$SystemUnderTest, $Argument> { @@ -53,7 +52,7 @@ public class GivenArgumentWhenSteps<$SystemUnderTest, $Argument> implements AndG @Override public <$Argument2> AndGivenTwoArguments<$SystemUnderTest, $Argument, $Argument2> andArgument( - Class<$Argument2> mutableArgumentClass, Consumer<$Argument2> givenStep) { + Class<$Argument2> mutableArgumentClass, CheckedConsumer<$Argument2> givenStep) { preparation.recordGivenStep(mutableArgumentClass, givenStep); return new GivenTwoArgumentsWhenSteps<>(preparation); } diff --git a/test-as-you-think-core/src/main/java/testasyouthink/GivenTwoArgumentsWhenSteps.java b/test-as-you-think-core/src/main/java/testasyouthink/GivenTwoArgumentsWhenSteps.java index fb76776..ba44a63 100644 --- a/test-as-you-think-core/src/main/java/testasyouthink/GivenTwoArgumentsWhenSteps.java +++ b/test-as-you-think-core/src/main/java/testasyouthink/GivenTwoArgumentsWhenSteps.java @@ -27,14 +27,13 @@ import testasyouthink.GivenWhenThenDsl.VerificationStage.Then; import testasyouthink.GivenWhenThenDsl.VerificationStage.ThenFailure; import testasyouthink.GivenWhenThenDsl.VerificationStage.ThenWithoutResult; +import testasyouthink.function.CheckedConsumer; import testasyouthink.function.CheckedSupplier; import testasyouthink.function.CheckedTriConsumer; import testasyouthink.function.CheckedTriFunction; import testasyouthink.function.Functions; import testasyouthink.preparation.Preparation; -import java.util.function.Consumer; - public class GivenTwoArgumentsWhenSteps<$SystemUnderTest, $Argument1, $Argument2> implements AndGivenTwoArguments<$SystemUnderTest, $Argument1, $Argument2> { @@ -55,7 +54,7 @@ public class GivenTwoArgumentsWhenSteps<$SystemUnderTest, $Argument1, $Argument2 @Override public <$Argument3> WhenApplyingThreeArguments<$SystemUnderTest, $Argument1, $Argument2, $Argument3> andArgument( - Class<$Argument3> mutableArgumentClass, Consumer<$Argument3> givenStep) { + Class<$Argument3> mutableArgumentClass, CheckedConsumer<$Argument3> givenStep) { preparation.recordGivenStep(mutableArgumentClass, givenStep); return new GivenThreeArgumentsWhenSteps<>(preparation); } diff --git a/test-as-you-think-core/src/main/java/testasyouthink/GivenWhenContext.java b/test-as-you-think-core/src/main/java/testasyouthink/GivenWhenContext.java index af5149f..0d9b6f9 100644 --- a/test-as-you-think-core/src/main/java/testasyouthink/GivenWhenContext.java +++ b/test-as-you-think-core/src/main/java/testasyouthink/GivenWhenContext.java @@ -22,29 +22,35 @@ package testasyouthink; -import testasyouthink.execution.Event; +import testasyouthink.execution.Execution; import testasyouthink.preparation.Preparation; -class GivenWhenContext<$SystemUnderTest, $Result> { +import java.util.Optional; + +public class GivenWhenContext<$SystemUnderTest, $Result> { private final Preparation<$SystemUnderTest> preparation; - private final Event<$SystemUnderTest, $Result> event; - private $Result result; + private final Execution<$SystemUnderTest, $Result> execution; + private Optional<$Result> result; - GivenWhenContext(Preparation<$SystemUnderTest> preparation, Event<$SystemUnderTest, $Result> event) { + GivenWhenContext(Preparation<$SystemUnderTest> preparation, Execution<$SystemUnderTest, $Result> execution) { this.preparation = preparation; - this.event = event; + this.execution = execution; + } + + public void prepareFixturesSeparately() { + preparation.prepareFixturesSeparately(); } - $Result returnResultOrVoid() { + public $Result returnResultOrVoid() { if (result == null) { preparation.prepareFixtures(); - result = event.happen(); + result = execution.run(); } - return result; + return result.orElse(null); } - $SystemUnderTest getSystemUnderTest() { + public $SystemUnderTest getSystemUnderTest() { return preparation .supplySut() .get(); diff --git a/test-as-you-think-core/src/main/java/testasyouthink/GivenWhenSteps.java b/test-as-you-think-core/src/main/java/testasyouthink/GivenWhenSteps.java index f7f806d..1e02c8e 100644 --- a/test-as-you-think-core/src/main/java/testasyouthink/GivenWhenSteps.java +++ b/test-as-you-think-core/src/main/java/testasyouthink/GivenWhenSteps.java @@ -30,13 +30,11 @@ import testasyouthink.GivenWhenThenDsl.VerificationStage.ThenWithoutResult; import testasyouthink.function.CheckedConsumer; import testasyouthink.function.CheckedFunction; +import testasyouthink.function.CheckedRunnable; import testasyouthink.function.CheckedSupplier; import testasyouthink.function.Functions; import testasyouthink.preparation.Preparation; -import java.util.function.Consumer; -import java.util.function.Supplier; - public class GivenWhenSteps<$SystemUnderTest> implements Given<$SystemUnderTest>, AndGiven<$SystemUnderTest> { private final Functions functions = Functions.INSTANCE; @@ -51,41 +49,41 @@ public class GivenWhenSteps<$SystemUnderTest> implements Given<$SystemUnderTest> preparation = new Preparation<>(systemUnderTest); } - GivenWhenSteps(Supplier<$SystemUnderTest> sutSupplier) { + GivenWhenSteps(CheckedSupplier<$SystemUnderTest> sutSupplier) { preparation = new Preparation<>(sutSupplier); } @Override - public AndGiven<$SystemUnderTest> given(Runnable givenStep) { + public AndGiven<$SystemUnderTest> given(CheckedRunnable givenStep) { preparation.recordGivenStep(givenStep); return this; } @Override - public AndGiven<$SystemUnderTest> given(Consumer<$SystemUnderTest> givenStep) { + public AndGiven<$SystemUnderTest> given(CheckedConsumer<$SystemUnderTest> givenStep) { preparation.recordGivenStep(givenStep); return this; } @Override - public AndGiven<$SystemUnderTest> given(String fixtureSpecification, Runnable givenStep) { + public AndGiven<$SystemUnderTest> given(String fixtureSpecification, CheckedRunnable givenStep) { preparation.recordGivenStep(givenStep); return this; } @Override - public AndGiven<$SystemUnderTest> given(String fixtureSpecification, Consumer<$SystemUnderTest> givenStep) { + public AndGiven<$SystemUnderTest> given(String fixtureSpecification, CheckedConsumer<$SystemUnderTest> givenStep) { preparation.recordGivenStep(givenStep); return this; } @Override - public AndGiven<$SystemUnderTest> and(String fixtureSpecification, Runnable givenStep) { + public AndGiven<$SystemUnderTest> and(String fixtureSpecification, CheckedRunnable givenStep) { return given(fixtureSpecification, givenStep); } @Override - public AndGiven<$SystemUnderTest> and(String fixtureSpecification, Consumer<$SystemUnderTest> givenStep) { + public AndGiven<$SystemUnderTest> and(String fixtureSpecification, CheckedConsumer<$SystemUnderTest> givenStep) { return given(fixtureSpecification, givenStep); } @@ -103,7 +101,7 @@ public class GivenWhenSteps<$SystemUnderTest> implements Given<$SystemUnderTest> @Override public <$Argument> AndGivenArgument<$SystemUnderTest, $Argument> givenArgument( - Class<$Argument> mutableArgumentClass, Consumer<$Argument> givenStep) { + Class<$Argument> mutableArgumentClass, CheckedConsumer<$Argument> givenStep) { preparation.recordGivenStep(mutableArgumentClass, givenStep); return new GivenArgumentWhenSteps<>(preparation); } diff --git a/test-as-you-think-core/src/main/java/testasyouthink/GivenWhenThenDsl.java b/test-as-you-think-core/src/main/java/testasyouthink/GivenWhenThenDsl.java index 230ef05..01228fe 100644 --- a/test-as-you-think-core/src/main/java/testasyouthink/GivenWhenThenDsl.java +++ b/test-as-you-think-core/src/main/java/testasyouthink/GivenWhenThenDsl.java @@ -33,19 +33,17 @@ import testasyouthink.function.CheckedBiFunction; import testasyouthink.function.CheckedConsumer; import testasyouthink.function.CheckedFunction; +import testasyouthink.function.CheckedPredicate; import testasyouthink.function.CheckedQuadriConsumer; import testasyouthink.function.CheckedQuadriFunction; +import testasyouthink.function.CheckedRunnable; import testasyouthink.function.CheckedSupplier; +import testasyouthink.function.CheckedSuppliers.CheckedBooleanSupplier; import testasyouthink.function.CheckedTriConsumer; import testasyouthink.function.CheckedTriFunction; import java.time.Duration; import java.util.List; -import java.util.function.BiConsumer; -import java.util.function.BiPredicate; -import java.util.function.BooleanSupplier; -import java.util.function.Consumer; -import java.util.function.Predicate; public interface GivenWhenThenDsl { @@ -53,20 +51,20 @@ interface PreparationStage { interface Given<$SystemUnderTest> extends GivenArgument<$SystemUnderTest>, When<$SystemUnderTest> { - AndGiven<$SystemUnderTest> given(Runnable givenStep); + AndGiven<$SystemUnderTest> given(CheckedRunnable givenStep); - AndGiven<$SystemUnderTest> given(Consumer<$SystemUnderTest> givenStep); + AndGiven<$SystemUnderTest> given(CheckedConsumer<$SystemUnderTest> givenStep); - AndGiven<$SystemUnderTest> given(String fixtureSpecification, Runnable givenStep); + AndGiven<$SystemUnderTest> given(String fixtureSpecification, CheckedRunnable givenStep); - AndGiven<$SystemUnderTest> given(String fixtureSpecification, Consumer<$SystemUnderTest> givenStep); + AndGiven<$SystemUnderTest> given(String fixtureSpecification, CheckedConsumer<$SystemUnderTest> givenStep); } interface AndGiven<$SystemUnderTest> extends GivenArgument<$SystemUnderTest>, When<$SystemUnderTest> { - AndGiven<$SystemUnderTest> and(String fixtureSpecification, Runnable givenStep); + AndGiven<$SystemUnderTest> and(String fixtureSpecification, CheckedRunnable givenStep); - AndGiven<$SystemUnderTest> and(String fixtureSpecification, Consumer<$SystemUnderTest> givenStep); + AndGiven<$SystemUnderTest> and(String fixtureSpecification, CheckedConsumer<$SystemUnderTest> givenStep); } interface GivenArgument<$SystemUnderTest> { @@ -81,7 +79,7 @@ interface GivenArgument<$SystemUnderTest> { $Argument argument); <$Argument> AndGivenArgument<$SystemUnderTest, $Argument> givenArgument( - Class<$Argument> mutableArgumentClass, Consumer<$Argument> givenStep); + Class<$Argument> mutableArgumentClass, CheckedConsumer<$Argument> givenStep); } interface AndGivenArgument<$SystemUnderTest, $Argument> extends WhenApplyingOneArgument<$SystemUnderTest, @@ -91,7 +89,7 @@ interface AndGivenArgument<$SystemUnderTest, $Argument> extends WhenApplyingOneA CheckedSupplier<$Argument2> givenStep); <$Argument2> AndGivenTwoArguments<$SystemUnderTest, $Argument, $Argument2> andArgument( - Class<$Argument2> mutableArgumentClass, Consumer<$Argument2> givenStep); + Class<$Argument2> mutableArgumentClass, CheckedConsumer<$Argument2> givenStep); <$Argument2> AndGivenTwoArguments<$SystemUnderTest, $Argument, $Argument2> andArgument(String description, CheckedSupplier<$Argument2> givenStep); @@ -107,7 +105,7 @@ interface AndGivenTwoArguments<$SystemUnderTest, $Argument1, $Argument2> extends CheckedSupplier<$Argument3> givenStep); <$Argument3> WhenApplyingThreeArguments<$SystemUnderTest, $Argument1, $Argument2, $Argument3> andArgument( - Class<$Argument3> mutableArgumentClass, Consumer<$Argument3> givenStep); + Class<$Argument3> mutableArgumentClass, CheckedConsumer<$Argument3> givenStep); <$Argument3> WhenApplyingThreeArguments<$SystemUnderTest, $Argument1, $Argument2, $Argument3> andArgument( String description, CheckedSupplier<$Argument3> givenStep); @@ -189,72 +187,74 @@ interface VerificationStage { interface Then<$SystemUnderTest, $Result> { - AndThen<$SystemUnderTest, $Result> then(Consumer<$Result> thenStep); + AndThen<$SystemUnderTest, $Result> then(CheckedConsumer<$Result> thenStep); - AndThen<$SystemUnderTest, $Result> then(String expectationSpecification, Consumer<$Result> thenStep); + AndThen<$SystemUnderTest, $Result> then(String expectationSpecification, CheckedConsumer<$Result> thenStep); - AndThen<$SystemUnderTest, $Result> then(Runnable thenStep); + AndThen<$SystemUnderTest, $Result> then(CheckedRunnable thenStep); - AndThen<$SystemUnderTest, $Result> then(String expectationSpecification, Runnable thenStep); + AndThen<$SystemUnderTest, $Result> then(String expectationSpecification, CheckedRunnable thenStep); - AndThen<$SystemUnderTest, $Result> then(Predicate<$Result> thenStep); + AndThen<$SystemUnderTest, $Result> then(CheckedPredicate<$Result> thenStep); AndThen<$SystemUnderTest, $Result> thenSutRepliesWithin(long timeLimit); - AndThen<$SystemUnderTest, $Result> thenSutRepliesWithin(Duration duration); + AndThen<$SystemUnderTest, $Result> thenSutRepliesWithin(Duration durationLimit); - void then(List> thenSteps); + void then(List> thenSteps); - void then(BiConsumer<$SystemUnderTest, $Result> thenStep); + void then(CheckedConsumer<$Result> thenStepAboutResult, + CheckedConsumer<$SystemUnderTest> thenStepAboutSystemUnderTest); - void then(BiPredicate<$SystemUnderTest, $Result> thenStep); - - void then(Predicate<$Result> thenStepAboutResult, Predicate<$SystemUnderTest> thenStepAboutSystemUnderTest); + void then(CheckedPredicate<$Result> thenStepAboutResult, + CheckedPredicate<$SystemUnderTest> thenStepAboutSystemUnderTest); } interface AndThen<$SystemUnderTest, $Result> { - AndThen<$SystemUnderTest, $Result> and(Consumer<$Result> thenStep); + AndThen<$SystemUnderTest, $Result> and(CheckedConsumer<$Result> thenStep); - AndThen<$SystemUnderTest, $Result> and(String expectationSpecification, Consumer<$Result> thenStep); + AndThen<$SystemUnderTest, $Result> and(String expectationSpecification, CheckedConsumer<$Result> thenStep); - AndThen<$SystemUnderTest, $Result> and(Runnable thenStep); + AndThen<$SystemUnderTest, $Result> and(CheckedRunnable thenStep); - AndThen<$SystemUnderTest, $Result> and(String expectationSpecification, Runnable thenStep); + AndThen<$SystemUnderTest, $Result> and(String expectationSpecification, CheckedRunnable thenStep); - AndThen<$SystemUnderTest, $Result> and(Predicate<$Result> thenStep); + AndThen<$SystemUnderTest, $Result> and(CheckedPredicate<$Result> thenStep); } interface ThenWithoutResult<$SystemUnderTest> { - AndThenWithoutResult<$SystemUnderTest> then(Runnable thenStep); + AndThenWithoutResult<$SystemUnderTest> then(CheckedRunnable thenStep); - AndThenWithoutResult<$SystemUnderTest> then(String expectationSpecification, Runnable thenStep); + AndThenWithoutResult<$SystemUnderTest> then(String expectationSpecification, CheckedRunnable thenStep); - AndThenWithoutResult<$SystemUnderTest> then(Consumer<$SystemUnderTest> thenStep); + AndThenWithoutResult<$SystemUnderTest> then(CheckedConsumer<$SystemUnderTest> thenStep); AndThenWithoutResult<$SystemUnderTest> then(String expectationSpecification, - Consumer<$SystemUnderTest> thenStep); + CheckedConsumer<$SystemUnderTest> thenStep); - AndThenWithoutResult<$SystemUnderTest> then(BooleanSupplier thenStep); + AndThenWithoutResult<$SystemUnderTest> then(CheckedBooleanSupplier thenStep); AndThenWithoutResult<$SystemUnderTest> thenSutRepliesWithin(long timeLimit); - AndThenWithoutResult<$SystemUnderTest> thenSutRepliesWithin(Duration duration); + AndThenWithoutResult<$SystemUnderTest> thenSutRepliesWithin(Duration durationLimit); + + void thenItSucceeds(); } interface AndThenWithoutResult<$SystemUnderTest> { - AndThenWithoutResult<$SystemUnderTest> and(Runnable thenStep); + AndThenWithoutResult<$SystemUnderTest> and(CheckedRunnable thenStep); - AndThenWithoutResult<$SystemUnderTest> and(String expectationSpecification, Runnable thenStep); + AndThenWithoutResult<$SystemUnderTest> and(String expectationSpecification, CheckedRunnable thenStep); - AndThenWithoutResult<$SystemUnderTest> and(Consumer<$SystemUnderTest> thenStep); + AndThenWithoutResult<$SystemUnderTest> and(CheckedConsumer<$SystemUnderTest> thenStep); AndThenWithoutResult<$SystemUnderTest> and(String expectationSpecification, - Consumer<$SystemUnderTest> thenStep); + CheckedConsumer<$SystemUnderTest> thenStep); - AndThenWithoutResult<$SystemUnderTest> and(BooleanSupplier thenStep); + AndThenWithoutResult<$SystemUnderTest> and(CheckedBooleanSupplier thenStep); } interface ThenFailure { @@ -264,7 +264,7 @@ interface ThenFailure { interface AndThenFailure { - AndThenFailure becauseOf(Class expectedThrowableClass); + AndThenFailure becauseOf(Class expectedFailureClass); AndThenFailure withMessage(String expectedMessage); diff --git a/test-as-you-think-core/src/main/java/testasyouthink/TestAsYouThink.java b/test-as-you-think-core/src/main/java/testasyouthink/TestAsYouThink.java index 40007a8..8875a92 100644 --- a/test-as-you-think-core/src/main/java/testasyouthink/TestAsYouThink.java +++ b/test-as-you-think-core/src/main/java/testasyouthink/TestAsYouThink.java @@ -69,7 +69,8 @@ import testasyouthink.GivenWhenThenDsl.VerificationStage.Then; import testasyouthink.GivenWhenThenDsl.VerificationStage.ThenFailure; import testasyouthink.GivenWhenThenDsl.VerificationStage.ThenWithoutResult; -import testasyouthink.execution.ExecutionError; +import testasyouthink.execution.Execution; +import testasyouthink.function.CheckedConsumer; import testasyouthink.function.CheckedFunction; import testasyouthink.function.CheckedRunnable; import testasyouthink.function.CheckedSupplier; @@ -120,11 +121,8 @@ import java.io.InputStream; import java.util.concurrent.Future; -import java.util.function.Consumer; -import java.util.function.Supplier; import static org.assertj.core.api.Assertions.assertThat; -import static testasyouthink.execution.Event.EXECUTION_FAILURE_MESSAGE; public class TestAsYouThink { @@ -137,7 +135,7 @@ private TestAsYouThink() {} return new GivenWhenSteps<>(systemUnderTest); } - public static <$SystemUnderTest> Given<$SystemUnderTest> givenSut(Supplier<$SystemUnderTest> givenSutStep) { + public static <$SystemUnderTest> Given<$SystemUnderTest> givenSut(CheckedSupplier<$SystemUnderTest> givenSutStep) { return new GivenWhenSteps<>(givenSutStep); } @@ -146,15 +144,15 @@ private TestAsYouThink() {} } public static <$SystemUnderTest> AndGiven<$SystemUnderTest> givenSut(Class<$SystemUnderTest> sutClass, - Consumer<$SystemUnderTest> givenStep) { + CheckedConsumer<$SystemUnderTest> givenStep) { return givenSutClass(sutClass).given(givenStep); } - public static ThenWithoutResult when(Runnable whenStep) { + public static ThenWithoutResult when(CheckedRunnable whenStep) { return thenStepFactory.createThenStep(functions.toCheckedConsumer(whenStep)); } - public static <$Result> Then when(Supplier<$Result> whenStep) { + public static <$Result> Then when(CheckedSupplier<$Result> whenStep) { return thenStepFactory.createThenStep(functions.toCheckedFunction(whenStep)); } @@ -168,23 +166,17 @@ public static ThenFailure whenOutsideOperatingConditions(CheckedRunnable whenSte } private static <$Result> $Result result(CheckedSupplier<$Result> whenStep) { - $Result result; - try { - result = whenStep.get(); - } catch (Throwable throwable) { - throw new ExecutionError(EXECUTION_FAILURE_MESSAGE, throwable); - } - return result; + return Execution + .of(whenStep) + .run() + .orElse(null); } private static <$Element> $Element[] arrayAsResult(CheckedArraySupplier<$Element> whenStep) { - $Element[] result; - try { - result = whenStep.get(); - } catch (Throwable throwable) { - throw new ExecutionError(EXECUTION_FAILURE_MESSAGE, throwable); - } - return result; + return Execution + .of(whenStep) + .run() + .orElse(null); } public static <$ActualResult> AbstractObjectAssert resultOf( diff --git a/test-as-you-think-core/src/main/java/testasyouthink/ThenStep.java b/test-as-you-think-core/src/main/java/testasyouthink/ThenStep.java index 3c368e4..342c1dc 100644 --- a/test-as-you-think-core/src/main/java/testasyouthink/ThenStep.java +++ b/test-as-you-think-core/src/main/java/testasyouthink/ThenStep.java @@ -26,158 +26,133 @@ import testasyouthink.GivenWhenThenDsl.VerificationStage.AndThenFailure; import testasyouthink.GivenWhenThenDsl.VerificationStage.Then; import testasyouthink.GivenWhenThenDsl.VerificationStage.ThenFailure; -import testasyouthink.verification.Assertions; +import testasyouthink.function.CheckedConsumer; +import testasyouthink.function.CheckedPredicate; +import testasyouthink.function.CheckedRunnable; +import testasyouthink.verification.Verification; import java.time.Duration; import java.util.List; -import java.util.function.BiConsumer; -import java.util.function.BiPredicate; -import java.util.function.Consumer; -import java.util.function.Predicate; - -import static org.assertj.core.api.Assertions.assertThat; public class ThenStep<$SystemUnderTest, $Result> implements Then<$SystemUnderTest, $Result>, AndThen<$SystemUnderTest, $Result>, ThenFailure, AndThenFailure { - private static final String MISSING_EXCEPTION = "Expecting a failure, but it was missing."; - private final GivenWhenContext<$SystemUnderTest, $Result> context; + private Verification<$SystemUnderTest, $Result> verification; ThenStep(GivenWhenContext<$SystemUnderTest, $Result> context) { - this.context = context; + verification = new Verification<>(context); } @Override - public AndThen<$SystemUnderTest, $Result> then(Consumer<$Result> thenStep) { - thenStep.accept(context.returnResultOrVoid()); + public AndThen<$SystemUnderTest, $Result> then(CheckedConsumer<$Result> thenStep) { + verification.verifyResult(thenStep); return this; } @Override - public void then(BiConsumer<$SystemUnderTest, $Result> thenStep) { - thenStep.accept(context.getSystemUnderTest(), context.returnResultOrVoid()); - } - - @Override - public AndThen<$SystemUnderTest, $Result> then(Runnable thenStep) { - context.returnResultOrVoid(); - thenStep.run(); + public AndThen<$SystemUnderTest, $Result> then(CheckedRunnable thenStep) { + verification.verify(thenStep); return this; } @Override - public AndThen<$SystemUnderTest, $Result> then(String expectationSpecification, Consumer<$Result> thenStep) { - then(thenStep); - return this; + public AndThen<$SystemUnderTest, $Result> then(String expectationSpecification, CheckedConsumer<$Result> thenStep) { + return then(thenStep); } @Override - public AndThen<$SystemUnderTest, $Result> then(String expectationSpecification, Runnable thenStep) { - then(thenStep); - return this; + public AndThen<$SystemUnderTest, $Result> then(String expectationSpecification, CheckedRunnable thenStep) { + return then(thenStep); } @Override - public AndThen<$SystemUnderTest, $Result> then(Predicate<$Result> thenStep) { - assertThat(thenStep.test(context.returnResultOrVoid())).isTrue(); + public AndThen<$SystemUnderTest, $Result> then(CheckedPredicate<$Result> thenStep) { + verification.verifyResult(thenStep); return this; } @Override - public void then(List> thenSteps) { - assertThat(thenSteps - .stream() - .reduce(Predicate::and) - .get() - .test(context.returnResultOrVoid())).isTrue(); + public void then(List> thenSteps) { + verification.verifyResult(thenSteps); } @Override - public void then(BiPredicate<$SystemUnderTest, $Result> thenStep) { - assertThat(thenStep.test(context.getSystemUnderTest(), context.returnResultOrVoid())).isTrue(); + public void then(CheckedConsumer<$Result> thenStepAboutResult, + CheckedConsumer<$SystemUnderTest> thenStepAboutSystemUnderTest) { + verification.verifyResult(thenStepAboutResult); + verification.verifySut(thenStepAboutSystemUnderTest); } @Override - public void then(Predicate<$Result> thenStepAboutResult, Predicate<$SystemUnderTest> thenStepAboutSystemUnderTest) { - then(thenStepAboutResult); - assertThat(thenStepAboutSystemUnderTest.test(context.getSystemUnderTest())).isTrue(); + public void then(CheckedPredicate<$Result> thenStepAboutResult, + CheckedPredicate<$SystemUnderTest> thenStepAboutSystemUnderTest) { + verification.verifyResult(thenStepAboutResult); + verification.verifySut(thenStepAboutSystemUnderTest); } @Override - public AndThen<$SystemUnderTest, $Result> and(Consumer<$Result> thenStep) { - thenStep.accept(context.returnResultOrVoid()); - return this; + public AndThen<$SystemUnderTest, $Result> and(CheckedConsumer<$Result> thenStep) { + return then(thenStep); } @Override - public AndThen<$SystemUnderTest, $Result> and(Runnable thenStep) { - thenStep.run(); - return this; + public AndThen<$SystemUnderTest, $Result> and(CheckedRunnable thenStep) { + return then(thenStep); } @Override - public AndThen<$SystemUnderTest, $Result> and(String expectationSpecification, Consumer<$Result> thenStep) { + public AndThen<$SystemUnderTest, $Result> and(String expectationSpecification, CheckedConsumer<$Result> thenStep) { return then(expectationSpecification, thenStep); } @Override - public AndThen<$SystemUnderTest, $Result> and(Predicate<$Result> thenStep) { + public AndThen<$SystemUnderTest, $Result> and(CheckedPredicate<$Result> thenStep) { return then(thenStep); } @Override - public AndThen<$SystemUnderTest, $Result> and(String expectationSpecification, Runnable thenStep) { + public AndThen<$SystemUnderTest, $Result> and(String expectationSpecification, CheckedRunnable thenStep) { return then(expectationSpecification, thenStep); } @Override public AndThenFailure thenItFails() { - Object result = context.returnResultOrVoid(); - if (result == null) { - throw new AssertionError(MISSING_EXCEPTION); - } else { - assertThat(context.returnResultOrVoid()).isInstanceOf(Throwable.class); - } + verification.verifyFailure(); return this; } @Override - public AndThenFailure becauseOf(Class expectedThrowableClass) { - assertThat(context.returnResultOrVoid()).isInstanceOf(expectedThrowableClass); + public AndThenFailure becauseOf(Class expectedFailureClass) { + verification.verifyFailure(expectedFailureClass); return this; } @Override public AndThenFailure withMessage(String expectedMessage) { - assertThat((Throwable) context.returnResultOrVoid()).hasMessage(expectedMessage); + verification.verifyFailureMessage(expectedMessage); return this; } @Override public AndThenFailure havingCause(Class expectedCauseClass) { - assertThat((Throwable) context.returnResultOrVoid()).hasCauseInstanceOf(expectedCauseClass); + verification.verifyFailureCause(expectedCauseClass); return this; } @Override public AndThenFailure withCauseMessage(String expectedMessage) { - assertThat(((Throwable) context.returnResultOrVoid()).getCause()).hasMessage(expectedMessage); + verification.verifyFailureCauseMessage(expectedMessage); return this; } @Override public AndThen<$SystemUnderTest, $Result> thenSutRepliesWithin(long timeLimit) { - Assertions - .assertThat(context::returnResultOrVoid) - .spendsAtMost(timeLimit); - return this; + return thenSutRepliesWithin(Duration.ofMillis(timeLimit)); } @Override - public AndThen<$SystemUnderTest, $Result> thenSutRepliesWithin(Duration duration) { - Assertions - .assertThat(context::returnResultOrVoid) - .spendsAtMost(duration); + public AndThen<$SystemUnderTest, $Result> thenSutRepliesWithin(Duration durationLimit) { + verification.verify(durationLimit); return this; } } diff --git a/test-as-you-think-core/src/main/java/testasyouthink/ThenStepFactory.java b/test-as-you-think-core/src/main/java/testasyouthink/ThenStepFactory.java index 5aa705d..d885349 100644 --- a/test-as-you-think-core/src/main/java/testasyouthink/ThenStepFactory.java +++ b/test-as-you-think-core/src/main/java/testasyouthink/ThenStepFactory.java @@ -22,7 +22,7 @@ package testasyouthink; -import testasyouthink.execution.Event; +import testasyouthink.execution.Execution; import testasyouthink.function.CheckedConsumer; import testasyouthink.function.CheckedFunction; import testasyouthink.preparation.Preparation; @@ -33,15 +33,15 @@ enum ThenStepFactory { <$SystemUnderTest, $Result> ThenStep<$SystemUnderTest, $Result> createThenStep( Preparation<$SystemUnderTest> preparation, CheckedFunction<$SystemUnderTest, $Result> whenStep) { - Event<$SystemUnderTest, $Result> event = new Event<>(preparation.supplySut(), whenStep); - GivenWhenContext<$SystemUnderTest, $Result> context = new GivenWhenContext<>(preparation, event); + Execution<$SystemUnderTest, $Result> execution = new Execution<>(preparation.supplySut(), whenStep); + GivenWhenContext<$SystemUnderTest, $Result> context = new GivenWhenContext<>(preparation, execution); return new ThenStep<>(context); } <$SystemUnderTest> ThenWithoutResultStep<$SystemUnderTest> createThenStep(Preparation<$SystemUnderTest> preparation, CheckedConsumer<$SystemUnderTest> whenStep) { - Event<$SystemUnderTest, Void> event = new Event<>(preparation.supplySut(), whenStep); - GivenWhenContext<$SystemUnderTest, Void> context = new GivenWhenContext<>(preparation, event); + Execution<$SystemUnderTest, Void> execution = new Execution<>(preparation.supplySut(), whenStep); + GivenWhenContext<$SystemUnderTest, Void> context = new GivenWhenContext<>(preparation, execution); return new ThenWithoutResultStep<>(context); } diff --git a/test-as-you-think-core/src/main/java/testasyouthink/ThenWithoutResultStep.java b/test-as-you-think-core/src/main/java/testasyouthink/ThenWithoutResultStep.java index c5681dc..505cf18 100644 --- a/test-as-you-think-core/src/main/java/testasyouthink/ThenWithoutResultStep.java +++ b/test-as-you-think-core/src/main/java/testasyouthink/ThenWithoutResultStep.java @@ -24,101 +24,90 @@ import testasyouthink.GivenWhenThenDsl.VerificationStage.AndThenWithoutResult; import testasyouthink.GivenWhenThenDsl.VerificationStage.ThenWithoutResult; -import testasyouthink.verification.Assertions; +import testasyouthink.function.CheckedConsumer; +import testasyouthink.function.CheckedRunnable; +import testasyouthink.function.CheckedSuppliers.CheckedBooleanSupplier; +import testasyouthink.verification.Verification; import java.time.Duration; -import java.util.function.BooleanSupplier; -import java.util.function.Consumer; - -import static org.assertj.core.api.Assertions.assertThat; public class ThenWithoutResultStep<$SystemUnderTest> implements ThenWithoutResult<$SystemUnderTest>, AndThenWithoutResult<$SystemUnderTest> { - private final GivenWhenContext<$SystemUnderTest, Void> context; + private final Verification<$SystemUnderTest, Void> verification; - public ThenWithoutResultStep(GivenWhenContext<$SystemUnderTest, Void> context) { - this.context = context; + ThenWithoutResultStep(GivenWhenContext<$SystemUnderTest, Void> context) { + verification = new Verification<>(context); } @Override - public AndThenWithoutResult<$SystemUnderTest> then(Runnable thenStep) { - context.returnResultOrVoid(); - thenStep.run(); + public AndThenWithoutResult<$SystemUnderTest> then(CheckedRunnable thenStep) { + verification.verify(thenStep); return this; } @Override - public AndThenWithoutResult<$SystemUnderTest> then(String expectationSpecification, Runnable thenStep) { - context.returnResultOrVoid(); - thenStep.run(); - return this; + public AndThenWithoutResult<$SystemUnderTest> then(String expectationSpecification, CheckedRunnable thenStep) { + return then(thenStep); } @Override - public AndThenWithoutResult<$SystemUnderTest> then(Consumer<$SystemUnderTest> thenStep) { - context.returnResultOrVoid(); - thenStep.accept(context.getSystemUnderTest()); + public AndThenWithoutResult<$SystemUnderTest> then(CheckedConsumer<$SystemUnderTest> thenStep) { + verification.verifySut(thenStep); return this; } @Override - public AndThenWithoutResult<$SystemUnderTest> then(BooleanSupplier thenStep) { - context.returnResultOrVoid(); - assertThat(thenStep.getAsBoolean()).isTrue(); + public AndThenWithoutResult<$SystemUnderTest> then(CheckedBooleanSupplier thenStep) { + verification.verify(thenStep); return this; } @Override - public AndThenWithoutResult<$SystemUnderTest> and(Runnable thenStep) { - thenStep.run(); - return this; + public AndThenWithoutResult<$SystemUnderTest> and(CheckedRunnable thenStep) { + return then(thenStep); } @Override - public AndThenWithoutResult<$SystemUnderTest> and(String expectationSpecification, Runnable thenStep) { - thenStep.run(); - return this; + public AndThenWithoutResult<$SystemUnderTest> and(String expectationSpecification, CheckedRunnable thenStep) { + return then(thenStep); } @Override - public AndThenWithoutResult<$SystemUnderTest> and(Consumer<$SystemUnderTest> thenStep) { - thenStep.accept(context.getSystemUnderTest()); - return this; + public AndThenWithoutResult<$SystemUnderTest> and(CheckedConsumer<$SystemUnderTest> thenStep) { + return then(thenStep); } @Override - public AndThenWithoutResult<$SystemUnderTest> and(BooleanSupplier thenStep) { - assertThat(thenStep.getAsBoolean()).isTrue(); - return this; + public AndThenWithoutResult<$SystemUnderTest> and(CheckedBooleanSupplier thenStep) { + return then(thenStep); } @Override public AndThenWithoutResult<$SystemUnderTest> then(String expectationSpecification, - Consumer<$SystemUnderTest> thenStep) { + CheckedConsumer<$SystemUnderTest> thenStep) { return then(thenStep); } @Override public AndThenWithoutResult<$SystemUnderTest> and(String expectationSpecification, - Consumer<$SystemUnderTest> thenStep) { - thenStep.accept(context.getSystemUnderTest()); - return this; + CheckedConsumer<$SystemUnderTest> thenStep) { + return then(expectationSpecification, thenStep); } @Override public AndThenWithoutResult<$SystemUnderTest> thenSutRepliesWithin(long timeLimit) { - Assertions - .assertThat(context::returnResultOrVoid) - .spendsAtMost(timeLimit); - return this; + return thenSutRepliesWithin(Duration.ofMillis(timeLimit)); } @Override - public AndThenWithoutResult<$SystemUnderTest> thenSutRepliesWithin(Duration duration) { - Assertions - .assertThat(context::returnResultOrVoid) - .spendsAtMost(duration); + public AndThenWithoutResult<$SystemUnderTest> thenSutRepliesWithin(Duration durationLimit) { + verification.verify(durationLimit); return this; } + + @Override + public void thenItSucceeds() { + verification.verifyNoFailure(); + } } diff --git a/test-as-you-think-core/src/main/java/testasyouthink/execution/Event.java b/test-as-you-think-core/src/main/java/testasyouthink/execution/Event.java index 68cd7c2..6adfbad 100644 --- a/test-as-you-think-core/src/main/java/testasyouthink/execution/Event.java +++ b/test-as-you-think-core/src/main/java/testasyouthink/execution/Event.java @@ -22,41 +22,21 @@ package testasyouthink.execution; -import testasyouthink.function.CheckedConsumer; import testasyouthink.function.CheckedFunction; -import testasyouthink.function.Functions; -import testasyouthink.preparation.PreparationError; import java.util.function.Supplier; -public class Event<$SystemUnderTest, $Result> { +class Event<$SystemUnderTest, $Result> { - public static final String EXECUTION_FAILURE_MESSAGE = "Fails to execute the target method " // - + "of the system under test because of an unexpected failure!"; - private final Functions functions = Functions.INSTANCE; private final Supplier<$SystemUnderTest> givenSutStep; private final CheckedFunction<$SystemUnderTest, $Result> whenStep; - public Event(Supplier<$SystemUnderTest> givenSutStep, CheckedFunction<$SystemUnderTest, $Result> whenStep) { + Event(Supplier<$SystemUnderTest> givenSutStep, CheckedFunction<$SystemUnderTest, $Result> whenStep) { this.givenSutStep = givenSutStep; this.whenStep = whenStep; } - public Event(Supplier<$SystemUnderTest> givenSutStep, CheckedConsumer<$SystemUnderTest> whenStep) { - this.givenSutStep = givenSutStep; - this.whenStep = functions.toFunction(whenStep); - } - - public $Result happen() { - $Result result; - try { - result = whenStep.apply(givenSutStep.get()); - } catch (PreparationError preparationError) { - throw preparationError; - } catch (Throwable throwable) { - throw new ExecutionError(EXECUTION_FAILURE_MESSAGE, throwable); - } - - return result; + $Result happen() throws Throwable { + return whenStep.apply(givenSutStep.get()); } } diff --git a/test-as-you-think-core/src/main/java/testasyouthink/execution/Execution.java b/test-as-you-think-core/src/main/java/testasyouthink/execution/Execution.java new file mode 100644 index 0000000..b3fa39a --- /dev/null +++ b/test-as-you-think-core/src/main/java/testasyouthink/execution/Execution.java @@ -0,0 +1,71 @@ +/*- + * #%L + * Test As You Think + * %% + * Copyright (C) 2017 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 + * . + * #L% + */ + +package testasyouthink.execution; + +import testasyouthink.function.CheckedConsumer; +import testasyouthink.function.CheckedFunction; +import testasyouthink.function.CheckedSupplier; +import testasyouthink.function.CheckedSuppliers.CheckedArraySupplier; +import testasyouthink.function.Functions; +import testasyouthink.preparation.PreparationError; + +import java.util.Optional; +import java.util.function.Supplier; + +public class Execution<$SystemUnderTest, $Result> { + + public static final String EXECUTION_FAILURE_MESSAGE = "Fails to execute the target method " // + + "of the system under test because of an unexpected failure!"; + private static final Functions FUNCTIONS = Functions.INSTANCE; + private final Event<$SystemUnderTest, $Result> event; + + public Execution(Supplier<$SystemUnderTest> givenSutStep, CheckedFunction<$SystemUnderTest, $Result> whenStep) { + event = new Event<>(givenSutStep, whenStep); + } + + public Execution(Supplier<$SystemUnderTest> givenSutStep, CheckedConsumer<$SystemUnderTest> whenStep) { + event = new Event<>(givenSutStep, FUNCTIONS.toFunction(whenStep)); + } + + public static <$Result> Execution of(CheckedSupplier<$Result> whenStep) { + return new Execution<>(noExplicitSut(), FUNCTIONS.toCheckedFunction(whenStep)); + } + + public static <$Element> Execution of(CheckedArraySupplier<$Element> whenStep) { + return new Execution<>(noExplicitSut(), FUNCTIONS.toCheckedFunction(whenStep)); + } + + private static Supplier noExplicitSut() { + return () -> null; + } + + public Optional<$Result> run() { + try { + return Optional.ofNullable(event.happen()); + } catch (PreparationError preparationError) { + throw preparationError; + } catch (Throwable throwable) { + throw new ExecutionError(EXECUTION_FAILURE_MESSAGE, throwable); + } + } +} diff --git a/test-as-you-think-core/src/main/java/testasyouthink/function/CheckedPredicate.java b/test-as-you-think-core/src/main/java/testasyouthink/function/CheckedPredicate.java new file mode 100644 index 0000000..837a08d --- /dev/null +++ b/test-as-you-think-core/src/main/java/testasyouthink/function/CheckedPredicate.java @@ -0,0 +1,48 @@ +/*- + * #%L + * Test As You Think + * %% + * Copyright (C) 2017 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 + * . + * #L% + */ + +package testasyouthink.function; + +import java.util.Objects; + +public interface CheckedPredicate<$Value> { + + static <$Value> CheckedPredicate<$Value> isEqual(Object targetRef) { + return (null == targetRef) ? Objects::isNull : object -> targetRef.equals(object); + } + + boolean test($Value value) throws Throwable; + + default CheckedPredicate<$Value> and(CheckedPredicate other) { + Objects.requireNonNull(other); + return value -> test(value) && other.test(value); + } + + default CheckedPredicate<$Value> negate() { + return value -> !test(value); + } + + default CheckedPredicate<$Value> or(CheckedPredicate other) { + Objects.requireNonNull(other); + return value -> test(value) || other.test(value); + } +} diff --git a/test-as-you-think-core/src/main/java/testasyouthink/function/Functions.java b/test-as-you-think-core/src/main/java/testasyouthink/function/Functions.java index eddc1c5..fa008db 100644 --- a/test-as-you-think-core/src/main/java/testasyouthink/function/Functions.java +++ b/test-as-you-think-core/src/main/java/testasyouthink/function/Functions.java @@ -22,6 +22,8 @@ package testasyouthink.function; +import testasyouthink.function.CheckedSuppliers.CheckedArraySupplier; + import java.util.Queue; import java.util.function.Consumer; import java.util.function.Supplier; @@ -39,7 +41,7 @@ public Consumer toConsumer(Runnable runnable) { return toBeConsumed -> runnable.run(); } - public CheckedConsumer toCheckedConsumer(Runnable runnable) { + public CheckedConsumer toCheckedConsumer(CheckedRunnable runnable) { return toBeConsumed -> runnable.run(); } @@ -50,7 +52,11 @@ public CheckedFunction toFunction(CheckedConsumer checkedConsume }; } - public CheckedFunction toCheckedFunction(Supplier supplier) { + public CheckedFunction toCheckedFunction(CheckedSupplier supplier) { + return Void -> supplier.get(); + } + + public CheckedFunction toCheckedFunction(CheckedArraySupplier supplier) { return Void -> supplier.get(); } @@ -82,46 +88,45 @@ public CheckedFunction toFunctionWithThrowableAsResult(CheckedR } public <$Target, $Argument, $Result> CheckedFunction<$Target, $Result> toFunction( - CheckedBiFunction<$Target, $Argument, $Result> biFunction, Queue arguments) { + CheckedBiFunction<$Target, $Argument, $Result> biFunction, Queue 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 arguments) { + CheckedTriFunction<$Target, $Argument1, $Argument2, $Result> triFunction, Queue 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 arguments) { + Queue arguments) { return toFunction(toBiFunction(toTriFunction(quadriFunction, arguments), arguments), arguments); } public <$Target, $Argument> CheckedConsumer<$Target> toConsumer(CheckedBiConsumer<$Target, $Argument> biConsumer, - Queue arguments) { + Queue arguments) { return target -> biConsumer.accept(target, ($Argument) arguments .remove() .get()); } public <$Target, $Argument1, $Argument2> CheckedConsumer<$Target> toConsumer( - CheckedTriConsumer<$Target, $Argument1, $Argument2> triConsumer, Queue arguments) { + CheckedTriConsumer<$Target, $Argument1, $Argument2> triConsumer, Queue arguments) { return toConsumer(toBiConsumer(triConsumer, arguments), arguments); } public <$Target, $Argument1, $Argument2, $Argument3> CheckedConsumer<$Target> toConsumer( CheckedQuadriConsumer<$Target, $Argument1, $Argument2, $Argument3> quadriConsumer, - Queue arguments) { + Queue 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 arguments) { + CheckedTriConsumer<$Target, $Argument1, $Argument2> triConsumer, Queue arguments) { return (target, argument1) -> triConsumer.accept(target, argument1, ($Argument2) arguments .remove() .get()); @@ -130,7 +135,7 @@ static class ConsumerUnitTransformation { static <$Target, $Argument1, $Argument2, $Argument3> CheckedTriConsumer<$Target, $Argument1, $Argument2> toTriConsumer( CheckedQuadriConsumer<$Target, $Argument1, $Argument2, $Argument3> quadriConsumer, - Queue arguments) { + Queue arguments) { return (target, argument1, argument2) -> quadriConsumer.accept(target, argument1, argument2, ($Argument3) arguments .remove() @@ -141,8 +146,7 @@ static class ConsumerUnitTransformation { static class FunctionUnitTransformation { static <$Target, $Argument1, $Argument2, $Result> CheckedBiFunction<$Target, $Argument1, $Result> toBiFunction( - CheckedTriFunction<$Target, $Argument1, $Argument2, $Result> triFunction, - Queue arguments) { + CheckedTriFunction<$Target, $Argument1, $Argument2, $Result> triFunction, Queue arguments) { return (target, argument1) -> triFunction.apply(target, argument1, ($Argument2) arguments .remove() .get()); @@ -151,7 +155,7 @@ static class FunctionUnitTransformation { static <$Target, $Argument1, $Argument2, $Argument3, $Result> CheckedTriFunction<$Target, $Argument1, $Argument2, $Result> toTriFunction( CheckedQuadriFunction<$Target, $Argument1, $Argument2, $Argument3, $Result> quadriFunction, - Queue arguments) { + Queue arguments) { return (target, argument1, argument2) -> quadriFunction.apply(target, argument1, argument2, ($Argument3) arguments .remove() diff --git a/test-as-you-think-core/src/main/java/testasyouthink/function/Memoized.java b/test-as-you-think-core/src/main/java/testasyouthink/function/Memoized.java new file mode 100644 index 0000000..9f0d533 --- /dev/null +++ b/test-as-you-think-core/src/main/java/testasyouthink/function/Memoized.java @@ -0,0 +1,47 @@ +/*- + * #%L + * Test As You Think + * %% + * Copyright (C) 2017 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 + * . + * #L% + */ + +package testasyouthink.function; + +import java.util.function.Supplier; + +public class Memoized<$Value> implements Supplier<$Value> { + + private Supplier<$Value> supplier; + private $Value value; + + private Memoized(Supplier<$Value> supplier) { + this.supplier = supplier; + } + + public static <$Value> Supplier<$Value> of(Supplier<$Value> supplier) { + return new Memoized<>(supplier); + } + + @Override + public $Value get() { + if (value == null) { + value = supplier.get(); + } + return value; + } +} diff --git a/test-as-you-think-core/src/main/java/testasyouthink/preparation/ArgumentPreparation.java b/test-as-you-think-core/src/main/java/testasyouthink/preparation/ArgumentPreparation.java index a0fdc54..54bd87f 100644 --- a/test-as-you-think-core/src/main/java/testasyouthink/preparation/ArgumentPreparation.java +++ b/test-as-you-think-core/src/main/java/testasyouthink/preparation/ArgumentPreparation.java @@ -22,26 +22,41 @@ package testasyouthink.preparation; +import testasyouthink.function.CheckedConsumer; import testasyouthink.function.CheckedSupplier; +import testasyouthink.function.Memoized; -import java.util.function.Consumer; +import java.util.function.Supplier; enum ArgumentPreparation { INSTANCE; - <$Argument> CheckedSupplier<$Argument> buildMutableArgumentSupplier(Class<$Argument> mutableArgumentClass, - Consumer<$Argument> givenStep) { - return () -> { + <$Argument> Supplier<$Argument> buildMutableArgumentSupplier(Class<$Argument> mutableArgumentClass, + CheckedConsumer<$Argument> givenStep) { + return Memoized.of(() -> { $Argument argument; try { argument = mutableArgumentClass.newInstance(); + givenStep.accept(argument); } catch (InstantiationException | IllegalAccessException exception) { throw new PreparationError("Fails to instantiate the argument of the " // + mutableArgumentClass.getName() + " type!", exception); + } catch (Throwable throwable) { + throw new PreparationError("Fails to prepare an argument of the " // + + mutableArgumentClass.getName() + " type for the target method!", throwable); } - givenStep.accept(argument); return argument; - }; + }); + } + + public <$Argument> Supplier<$Argument> buidArgumentSupplier(CheckedSupplier<$Argument> givenStep) { + return Memoized.of(() -> { + try { + return givenStep.get(); + } catch (Throwable throwable) { + throw new PreparationError("Fails to prepare an argument for the target method!", throwable); + } + }); } } diff --git a/test-as-you-think-core/src/main/java/testasyouthink/preparation/Preparation.java b/test-as-you-think-core/src/main/java/testasyouthink/preparation/Preparation.java index dbb3869..402c1ea 100644 --- a/test-as-you-think-core/src/main/java/testasyouthink/preparation/Preparation.java +++ b/test-as-you-think-core/src/main/java/testasyouthink/preparation/Preparation.java @@ -22,12 +22,13 @@ package testasyouthink.preparation; +import testasyouthink.function.CheckedConsumer; +import testasyouthink.function.CheckedRunnable; import testasyouthink.function.CheckedSupplier; import testasyouthink.function.Functions; -import java.util.ArrayList; +import java.util.ArrayDeque; import java.util.LinkedList; -import java.util.List; import java.util.Queue; import java.util.function.Consumer; import java.util.function.Supplier; @@ -37,13 +38,13 @@ 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> givenSteps; private Supplier<$SystemUnderTest> givenSutStep; - private final List> givenSteps; - private Queue argumentSuppliers; + private Queue argumentSuppliers; private $SystemUnderTest systemUnderTest; public Preparation() { - givenSteps = new ArrayList<>(); + givenSteps = new ArrayDeque<>(); argumentSuppliers = new LinkedList<>(); } @@ -57,33 +58,50 @@ public Preparation($SystemUnderTest systemUnderTest) { givenSutStep = sutPreparation.buildSutSupplier(systemUnderTest); } - public Preparation(Supplier<$SystemUnderTest> givenSutStep) { + public Preparation(CheckedSupplier<$SystemUnderTest> givenSutStep) { this(); - this.givenSutStep = givenSutStep; + this.givenSutStep = sutPreparation.buildSutSupplier(givenSutStep); } - public void recordGivenStep(Runnable givenStep) { - givenSteps.add(functions.toConsumer(givenStep)); + 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(Consumer<$SystemUnderTest> givenStep) { - givenSteps.add(givenStep); + public void recordGivenStep(CheckedConsumer<$SystemUnderTest> givenStep) { + givenSteps.add(sutPreparation.buildSutSupplier(givenStep)); } public <$Argument> void recordGivenStep(CheckedSupplier<$Argument> givenStep) { - argumentSuppliers.add(givenStep); + argumentSuppliers.add(argumentPreparation.buidArgumentSupplier(givenStep)); } - public <$Argument> void recordGivenStep(Class<$Argument> mutableArgumentClass, Consumer<$Argument> givenStep) { + public <$Argument> void recordGivenStep(Class<$Argument> mutableArgumentClass, + CheckedConsumer<$Argument> givenStep) { argumentSuppliers.add(argumentPreparation.buildMutableArgumentSupplier(mutableArgumentClass, givenStep)); } - public Queue getArgumentSuppliers() { + public Queue getArgumentSuppliers() { return argumentSuppliers; } public void prepareFixtures() { - givenSteps.forEach(step -> step.accept(systemUnderTest())); + $SystemUnderTest sutToPrepareAtFirst = systemUnderTest(); + while (!givenSteps.isEmpty()) { + givenSteps + .poll() + .accept(sutToPrepareAtFirst); + } + } + + public void prepareFixturesSeparately() { + prepareFixtures(); + argumentSuppliers.forEach(Supplier::get); } private $SystemUnderTest systemUnderTest() { diff --git a/test-as-you-think-core/src/main/java/testasyouthink/preparation/SutPreparation.java b/test-as-you-think-core/src/main/java/testasyouthink/preparation/SutPreparation.java index e43079d..7f5665f 100644 --- a/test-as-you-think-core/src/main/java/testasyouthink/preparation/SutPreparation.java +++ b/test-as-you-think-core/src/main/java/testasyouthink/preparation/SutPreparation.java @@ -22,6 +22,10 @@ package testasyouthink.preparation; +import testasyouthink.function.CheckedConsumer; +import testasyouthink.function.CheckedSupplier; + +import java.util.function.Consumer; import java.util.function.Supplier; enum SutPreparation { @@ -43,4 +47,24 @@ enum SutPreparation { return sut; }; } + + <$SystemUnderTest> Supplier<$SystemUnderTest> buildSutSupplier(CheckedSupplier<$SystemUnderTest> sutSupplier) { + return () -> { + try { + return sutSupplier.get(); + } catch (Throwable throwable) { + throw new PreparationError("Fails to prepare the system under test!", throwable); + } + }; + } + + public <$SystemUnderTest> Consumer<$SystemUnderTest> buildSutSupplier(CheckedConsumer<$SystemUnderTest> givenStep) { + return sut -> { + try { + givenStep.accept(sut); + } catch (Throwable throwable) { + throw new PreparationError("Fails to prepare the system under test!", throwable); + } + }; + } } diff --git a/test-as-you-think-core/src/main/java/testasyouthink/verification/Verification.java b/test-as-you-think-core/src/main/java/testasyouthink/verification/Verification.java new file mode 100644 index 0000000..0208320 --- /dev/null +++ b/test-as-you-think-core/src/main/java/testasyouthink/verification/Verification.java @@ -0,0 +1,161 @@ +/*- + * #%L + * Test As You Think + * %% + * Copyright (C) 2017 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 + * . + * #L% + */ + +package testasyouthink.verification; + +import testasyouthink.GivenWhenContext; +import testasyouthink.execution.ExecutionError; +import testasyouthink.function.CheckedConsumer; +import testasyouthink.function.CheckedPredicate; +import testasyouthink.function.CheckedRunnable; +import testasyouthink.function.CheckedSuppliers.CheckedBooleanSupplier; + +import java.time.Duration; +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +public class Verification<$SystemUnderTest, $Result> { + + private static final String MISSING_EXCEPTION = "Expecting a failure, but it was missing."; + private final GivenWhenContext<$SystemUnderTest, $Result> context; + + public Verification(GivenWhenContext<$SystemUnderTest, $Result> context) { + this.context = context; + } + + public void verifyResult(CheckedConsumer<$Result> expectation) { + $Result result = context.returnResultOrVoid(); + try { + expectation.accept(result); + } catch (AssertionError assertionError) { + throw assertionError; + } catch (Throwable throwable) { + throw new VerificationError("Fails to verify the result expectations!", throwable); + } + } + + public void verify(CheckedRunnable expectation) { + context.returnResultOrVoid(); + try { + expectation.run(); + } catch (AssertionError assertionError) { + throw assertionError; + } catch (Throwable throwable) { + throw new VerificationError("Fails to verify expectations!", throwable); + } + } + + public void verifyResult(CheckedPredicate<$Result> expectation) { + $Result result = context.returnResultOrVoid(); + try { + assertThat(expectation.test(result)).isTrue(); + } catch (AssertionError assertionError) { + throw assertionError; + } catch (Throwable throwable) { + throw new VerificationError("Fails to verify the result expectations!", throwable); + } + } + + public void verifySut(CheckedPredicate<$SystemUnderTest> expectation) { + context.returnResultOrVoid(); + try { + assertThat(expectation.test(context.getSystemUnderTest())).isTrue(); + } catch (AssertionError assertionError) { + throw assertionError; + } catch (Throwable throwable) { + throw new VerificationError("Fails to verify the expectations of the system under test!", throwable); + } + } + + public void verifySut(CheckedConsumer<$SystemUnderTest> expectation) { + context.returnResultOrVoid(); + try { + expectation.accept(context.getSystemUnderTest()); + } catch (AssertionError assertionError) { + throw assertionError; + } catch (Throwable throwable) { + throw new VerificationError("Fails to verify the expectations of the system under test!", throwable); + } + } + + public void verify(CheckedBooleanSupplier expectation) { + context.returnResultOrVoid(); + try { + assertThat(expectation.get()).isTrue(); + } catch (AssertionError assertionError) { + throw assertionError; + } catch (Throwable throwable) { + throw new VerificationError("Fails to verify expectations!", throwable); + } + } + + public void verifyResult(List> expectations) { + expectations + .stream() + .reduce(CheckedPredicate::and) + .ifPresent(this::verifyResult); + } + + public void verify(Duration durationLimit) { + context.prepareFixturesSeparately(); + Assertions + .assertThat(context::returnResultOrVoid) + .spendsAtMost(durationLimit); + } + + public void verifyFailure() { + Object result = context.returnResultOrVoid(); + if (result == null) { + throw new AssertionError(MISSING_EXCEPTION); + } else { + assertThat(context.returnResultOrVoid()).isInstanceOf(Throwable.class); + } + } + + public void verifyFailure(Class expectedFailureClass) { + assertThat(context.returnResultOrVoid()).isInstanceOf(expectedFailureClass); + } + + public void verifyFailureMessage(String expectedMessage) { + assertThat((Throwable) context.returnResultOrVoid()).hasMessage(expectedMessage); + } + + public void verifyFailureCause(Class expectedCauseClass) { + assertThat((Throwable) context.returnResultOrVoid()).hasCauseInstanceOf(expectedCauseClass); + } + + public void verifyFailureCauseMessage(String expectedMessage) { + assertThat(((Throwable) context.returnResultOrVoid()).getCause()).hasMessage(expectedMessage); + } + + public void verifyNoFailure() { + try { + context.returnResultOrVoid(); + } catch (ExecutionError executionError) { + assertThatThrownBy(() -> { + throw executionError.getCause(); + }).doesNotThrowAnyException(); + } + } +} \ No newline at end of file diff --git a/test-as-you-think-core/src/main/java/testasyouthink/verification/VerificationError.java b/test-as-you-think-core/src/main/java/testasyouthink/verification/VerificationError.java new file mode 100644 index 0000000..f65ed8d --- /dev/null +++ b/test-as-you-think-core/src/main/java/testasyouthink/verification/VerificationError.java @@ -0,0 +1,30 @@ +/*- + * #%L + * Test As You Think + * %% + * Copyright (C) 2017 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 + * . + * #L% + */ + +package testasyouthink.verification; + +public class VerificationError extends Error { + + public VerificationError(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/test-as-you-think-core/src/test/java/testasyouthink/GivenArgumentsTest.java b/test-as-you-think-core/src/test/java/testasyouthink/GivenArgumentsTest.java index 7721e8c..bee70af 100644 --- a/test-as-you-think-core/src/test/java/testasyouthink/GivenArgumentsTest.java +++ b/test-as-you-think-core/src/test/java/testasyouthink/GivenArgumentsTest.java @@ -26,17 +26,12 @@ import org.junit.After; import org.junit.Before; import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import testasyouthink.GivenArgumentsTest.Parameter.Mutable; -import testasyouthink.GivenArgumentsTest.Parameter.MutableButUninstantiable; import testasyouthink.fixture.GivenWhenThenDefinition; import testasyouthink.fixture.ParameterizedSystemUnderTest; import testasyouthink.fixture.SystemUnderTest; -import testasyouthink.preparation.PreparationError; import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.catchThrowable; import static org.easymock.EasyMock.anyObject; import static org.easymock.EasyMock.createStrictControl; import static org.easymock.EasyMock.expect; @@ -45,8 +40,6 @@ public class GivenArgumentsTest { - private static final Logger LOGGER = LoggerFactory.getLogger(GivenArgumentsTest.class); - private static final String GIVEN_STRING = "given argument"; private static final int GIVEN_INTEGER = 201705; private static final boolean GIVEN_BOOLEAN = false; @@ -107,30 +100,6 @@ class SystemUnderTestWithMutableParameter extends ParameterizedSystemUnderTest givenWhenThenDefinitionMock.thenTheActualResultIsInKeepingWithTheExpectedResult()); } - @Test - public void should_fail_to_instantiate_one_argument_with_its_mutable_type() throws Throwable { - //GIVEN - class SystemUnderTestWithUninstantiableParameter extends - ParameterizedSystemUnderTest {} - SystemUnderTestWithUninstantiableParameter sutWithUninstantiableParameter = mocksControl.createMock( - SystemUnderTestWithUninstantiableParameter.class); - mocksControl.replay(); - - // WHEN - Throwable thrown = catchThrowable(() -> givenSut(sutWithUninstantiableParameter) - .givenArgument(MutableButUninstantiable.class, mutableButUninstantiable -> {}) - .whenSutRuns(ParameterizedSystemUnderTest::voidMethodWithParameter) - .then(() -> {})); - - // THEN - LOGGER.debug("Stack trace", thrown); - assertThat(thrown) - .isInstanceOf(PreparationError.class) - .hasMessage("Fails to instantiate the argument of the " // - + "testasyouthink.GivenArgumentsTest$Parameter$MutableButUninstantiable type!") - .hasCauseInstanceOf(InstantiationException.class); - } - @Test public void should_receive_one_argument_with_its_description() { // GIVEN @@ -475,12 +444,5 @@ public void setForDemonstration(int forDemonstration) { this.forDemonstration = forDemonstration; } } - - public static class MutableButUninstantiable { - - public MutableButUninstantiable() throws InstantiationException { - throw new InstantiationException("Impossible to instantiate it!"); - } - } } } diff --git a/test-as-you-think-core/src/test/java/testasyouthink/GivenFailuresTest.java b/test-as-you-think-core/src/test/java/testasyouthink/GivenFailuresTest.java new file mode 100644 index 0000000..39d9a66 --- /dev/null +++ b/test-as-you-think-core/src/test/java/testasyouthink/GivenFailuresTest.java @@ -0,0 +1,466 @@ +/*- + * #%L + * Test As You Think + * %% + * Copyright (C) 2017 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 + * . + * #L% + */ + +package testasyouthink; + +import org.junit.Before; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import testasyouthink.GivenFailuresTest.Parameter.Mutable; +import testasyouthink.GivenFailuresTest.Parameter.MutableButUninstantiable; +import testasyouthink.fixture.GivenWhenThenDefinition; +import testasyouthink.fixture.ParameterizedSystemUnderTest; +import testasyouthink.fixture.SystemUnderTest; +import testasyouthink.fixture.UnexpectedException; +import testasyouthink.function.CheckedSupplier; +import testasyouthink.preparation.PreparationError; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.catchThrowable; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verifyZeroInteractions; +import static testasyouthink.TestAsYouThink.givenSut; +import static testasyouthink.TestAsYouThink.givenSutClass; + +public class GivenFailuresTest { + + private static final Logger LOGGER = LoggerFactory.getLogger(GivenFailuresTest.class); + private GivenWhenThenDefinition givenWhenThenDefinitionMock; + + @Before + public void prepareFixtures() { + // GIVEN + givenWhenThenDefinitionMock = mock(GivenWhenThenDefinition.class); + } + + @Test + public void should_fail_to_create_a_sut_instance() throws Throwable { + // WHEN + Throwable thrown = catchThrowable(() -> givenSutClass(SystemUnderTestFailingToBeInstantiated.class) + .when(SystemUnderTestFailingToBeInstantiated::voidMethod) + .then(() -> givenWhenThenDefinitionMock.thenTheActualResultIsInKeepingWithTheExpectedResult())); + + // THEN + LOGGER.debug("Stack trace", thrown); + assertThat(thrown) + .isInstanceOf(PreparationError.class) + .hasMessage("Fails to instantiate the system under test!") + .hasCauseInstanceOf(NullPointerException.class); + verifyZeroInteractions(givenWhenThenDefinitionMock); + } + + @Test + public void should_fail_to_supply_a_sut_instance() { + // WHEN + Throwable thrown = catchThrowable(() -> givenSut(() -> new SystemUnderTestFailingToBeInstantiated()) + .when(SystemUnderTestFailingToBeInstantiated::voidMethod) + .then(() -> givenWhenThenDefinitionMock.thenTheActualResultIsInKeepingWithTheExpectedResult())); + + // THEN + LOGGER.debug("Stack trace", thrown); + assertThat(thrown) + .isInstanceOf(PreparationError.class) + .hasMessage("Fails to prepare the system under test!") + .hasCauseInstanceOf(NullPointerException.class); + verifyZeroInteractions(givenWhenThenDefinitionMock); + } + + @Test + public void should_fail_to_prepare_the_sut_after_instantiating_it() { + // WHEN + Throwable thrown = catchThrowable(() -> givenSut(SystemUnderTest.class, sut -> { + throw new UnexpectedException(); + }) + .when(SystemUnderTest::voidMethod) + .then(() -> givenWhenThenDefinitionMock.thenTheActualResultIsInKeepingWithTheExpectedResult())); + + // THEN + LOGGER.debug("Stack trace", thrown); + assertThat(thrown) + .isInstanceOf(PreparationError.class) + .hasMessage("Fails to prepare the system under test!") + .hasCauseInstanceOf(UnexpectedException.class); + verifyZeroInteractions(givenWhenThenDefinitionMock); + } + + @Test + public void should_fail_to_prepare_the_sut() { + // WHEN + Throwable thrown = catchThrowable(() -> givenSutClass(SystemUnderTest.class) + .given(sut -> { + throw new UnexpectedException(); + }) + .when(SystemUnderTest::voidMethod) + .then(() -> givenWhenThenDefinitionMock.thenTheActualResultIsInKeepingWithTheExpectedResult())); + + // THEN + LOGGER.debug("Stack trace", thrown); + assertThat(thrown) + .isInstanceOf(PreparationError.class) + .hasMessage("Fails to prepare the system under test!") + .hasCauseInstanceOf(UnexpectedException.class); + verifyZeroInteractions(givenWhenThenDefinitionMock); + } + + @Test + public void should_fail_to_prepare_the_sut_with_its_specification() { + // WHEN + Throwable thrown = catchThrowable(() -> givenSutClass(SystemUnderTest.class) + .given("SUT specification", sut -> { + throw new UnexpectedException(); + }) + .when(SystemUnderTest::voidMethod) + .then(() -> givenWhenThenDefinitionMock.thenTheActualResultIsInKeepingWithTheExpectedResult())); + + // THEN + LOGGER.debug("Stack trace", thrown); + assertThat(thrown) + .isInstanceOf(PreparationError.class) + .hasMessage("Fails to prepare the system under test!") + .hasCauseInstanceOf(UnexpectedException.class); + verifyZeroInteractions(givenWhenThenDefinitionMock); + } + + @Test + public void should_fail_to_prepare_the_sut_with_its_specifications() { + // WHEN + Throwable thrown = catchThrowable(() -> givenSutClass(SystemUnderTest.class) + .given("SUT specification that passes", sut -> {}) + .and("SUT specification that fails", sut -> { + throw new UnexpectedException(); + }) + .when(SystemUnderTest::voidMethod) + .then(() -> givenWhenThenDefinitionMock.thenTheActualResultIsInKeepingWithTheExpectedResult())); + + // THEN + LOGGER.debug("Stack trace", thrown); + assertThat(thrown) + .isInstanceOf(PreparationError.class) + .hasMessage("Fails to prepare the system under test!") + .hasCauseInstanceOf(UnexpectedException.class); + verifyZeroInteractions(givenWhenThenDefinitionMock); + } + + @Test + public void should_fail_to_prepare_an_ordinary_fixture() { + // WHEN + Throwable thrown = catchThrowable(() -> givenSutClass(SystemUnderTest.class) + .given(() -> { + throw new UnexpectedException(); + }) + .when(SystemUnderTest::voidMethod) + .then(() -> givenWhenThenDefinitionMock.thenTheActualResultIsInKeepingWithTheExpectedResult())); + + // THEN + assertThat(thrown) + .isInstanceOf(PreparationError.class) + .hasMessage("Fails to prepare the test fixture!") + .hasCauseInstanceOf(UnexpectedException.class); + verifyZeroInteractions(givenWhenThenDefinitionMock); + } + + @Test + public void should_fail_to_prepare_an_ordinary_fixture_with_its_specification() { + // WHEN + Throwable thrown = catchThrowable(() -> givenSutClass(SystemUnderTest.class) + .given("fixture specification that fails", () -> { + throw new UnexpectedException(); + }) + .when(SystemUnderTest::voidMethod) + .then(() -> givenWhenThenDefinitionMock.thenTheActualResultIsInKeepingWithTheExpectedResult())); + + // THEN + assertThat(thrown) + .isInstanceOf(PreparationError.class) + .hasMessage("Fails to prepare the test fixture!") + .hasCauseInstanceOf(UnexpectedException.class); + verifyZeroInteractions(givenWhenThenDefinitionMock); + } + + @Test + public void should_fail_to_prepare_a_second_ordinary_fixture_with_its_specification() { + // WHEN + Throwable thrown = catchThrowable(() -> givenSutClass(SystemUnderTest.class) + .given("fixture specification that passes", () -> { + }) + .and("fixture specification that fails", () -> { + throw new UnexpectedException(); + }) + .when(SystemUnderTest::voidMethod) + .then(() -> givenWhenThenDefinitionMock.thenTheActualResultIsInKeepingWithTheExpectedResult())); + + // THEN + assertThat(thrown) + .isInstanceOf(PreparationError.class) + .hasMessage("Fails to prepare the test fixture!") + .hasCauseInstanceOf(UnexpectedException.class); + verifyZeroInteractions(givenWhenThenDefinitionMock); + } + + @Test + public void should_fail_to_supply_one_argument() { + // WHEN + Throwable thrown = catchThrowable(() -> givenSutClass(SystemUnderTest.class) + .givenArgument((CheckedSupplier) () -> { + throw new UnexpectedException(); + }) + .when(SystemUnderTest::voidMethodWithParameter) + .then(() -> givenWhenThenDefinitionMock.thenTheActualResultIsInKeepingWithTheExpectedResult())); + + // THEN + LOGGER.debug("Stack trace", thrown); + assertThat(thrown) + .isInstanceOf(PreparationError.class) + .hasMessage("Fails to prepare an argument for the target method!") + .hasCauseInstanceOf(UnexpectedException.class); + verifyZeroInteractions(givenWhenThenDefinitionMock); + } + + @Test + public void should_fail_to_supply_one_argument_with_its_specification() { + // WHEN + Throwable thrown = catchThrowable(() -> givenSutClass(SystemUnderTest.class) + .givenArgument("argument specification", (CheckedSupplier) () -> { + throw new UnexpectedException(); + }) + .when(SystemUnderTest::voidMethodWithParameter) + .then(() -> givenWhenThenDefinitionMock.thenTheActualResultIsInKeepingWithTheExpectedResult())); + + // THEN + LOGGER.debug("Stack trace", thrown); + assertThat(thrown) + .isInstanceOf(PreparationError.class) + .hasMessage("Fails to prepare an argument for the target method!") + .hasCauseInstanceOf(UnexpectedException.class); + verifyZeroInteractions(givenWhenThenDefinitionMock); + } + + @Test + public void should_fail_to_instantiate_one_argument_with_its_mutable_type() throws Throwable { + //GIVEN + class SystemUnderTestWithUninstantiableParameter extends + ParameterizedSystemUnderTest {} + SystemUnderTestWithUninstantiableParameter sutWithUninstantiableParameter = mock( + SystemUnderTestWithUninstantiableParameter.class); + + // WHEN + Throwable thrown = catchThrowable(() -> givenSut(sutWithUninstantiableParameter) + .givenArgument(MutableButUninstantiable.class, mutableButUninstantiable -> {}) + .whenSutRuns(ParameterizedSystemUnderTest::voidMethodWithParameter) + .then(() -> givenWhenThenDefinitionMock.thenTheActualResultIsInKeepingWithTheExpectedResult())); + + // THEN + LOGGER.debug("Stack trace", thrown); + assertThat(thrown) + .isInstanceOf(PreparationError.class) + .hasMessage("Fails to instantiate the argument of the " // + + "testasyouthink.GivenFailuresTest$Parameter$MutableButUninstantiable type!") + .hasCauseInstanceOf(InstantiationException.class); + verifyZeroInteractions(givenWhenThenDefinitionMock); + } + + @Test + public void should_fail_to_prepare_one_argument_with_its_mutable_type() throws Throwable { + //GIVEN + class SystemUnderTestWithMutableParameter extends ParameterizedSystemUnderTest {} + SystemUnderTestWithMutableParameter sutWithMutableParameter = mock(SystemUnderTestWithMutableParameter.class); + + // WHEN + Throwable thrown = catchThrowable(() -> givenSut(sutWithMutableParameter) + .givenArgument(Mutable.class, mutable -> { + throw new UnexpectedException(); + }) + .whenSutRuns(ParameterizedSystemUnderTest::voidMethodWithParameter) + .then(() -> givenWhenThenDefinitionMock.thenTheActualResultIsInKeepingWithTheExpectedResult())); + + // THEN + LOGGER.debug("Stack trace", thrown); + assertThat(thrown) + .isInstanceOf(PreparationError.class) + .hasMessage("Fails to prepare an argument of the " // + + "testasyouthink.GivenFailuresTest$Parameter$Mutable type for the target method!") + .hasCauseInstanceOf(UnexpectedException.class); + verifyZeroInteractions(givenWhenThenDefinitionMock); + } + + @Test + public void should_fail_to_supply_a_second_argument() { + // WHEN + Throwable thrown = catchThrowable(() -> givenSutClass(SystemUnderTest.class) + .givenArgument(() -> "argument") + .andArgument((CheckedSupplier) () -> { + throw new UnexpectedException(); + }) + .when(SystemUnderTest::voidMethodWithTwoParameters) + .then(() -> givenWhenThenDefinitionMock.thenTheActualResultIsInKeepingWithTheExpectedResult())); + + // THEN + LOGGER.debug("Stack trace", thrown); + assertThat(thrown) + .isInstanceOf(PreparationError.class) + .hasMessage("Fails to prepare an argument for the target method!") + .hasCauseInstanceOf(UnexpectedException.class); + verifyZeroInteractions(givenWhenThenDefinitionMock); + } + + @Test + public void should_fail_to_supply_a_second_argument_with_its_specification() { + // WHEN + Throwable thrown = catchThrowable(() -> givenSutClass(SystemUnderTest.class) + .givenArgument(() -> "argument") + .andArgument("argument specification", (CheckedSupplier) () -> { + throw new UnexpectedException(); + }) + .when(SystemUnderTest::voidMethodWithTwoParameters) + .then(() -> givenWhenThenDefinitionMock.thenTheActualResultIsInKeepingWithTheExpectedResult())); + + // THEN + LOGGER.debug("Stack trace", thrown); + assertThat(thrown) + .isInstanceOf(PreparationError.class) + .hasMessage("Fails to prepare an argument for the target method!") + .hasCauseInstanceOf(UnexpectedException.class); + verifyZeroInteractions(givenWhenThenDefinitionMock); + } + + @Test + public void should_fail_to_prepare_a_second_argument_with_its_mutable_type() throws Throwable { + //GIVEN + class SystemUnderTestWithMutableParameter extends ParameterizedSystemUnderTest {} + SystemUnderTestWithMutableParameter sutWithMutableParameters = mock(SystemUnderTestWithMutableParameter.class); + + // WHEN + Throwable thrown = catchThrowable(() -> givenSut(sutWithMutableParameters) + .givenArgument(Mutable.class, mutable -> {}) + .andArgument(Mutable.class, mutable -> { + throw new UnexpectedException(); + }) + .whenSutRuns(ParameterizedSystemUnderTest::voidMethodWithTwoParameters) + .then(() -> givenWhenThenDefinitionMock.thenTheActualResultIsInKeepingWithTheExpectedResult())); + + // THEN + LOGGER.debug("Stack trace", thrown); + assertThat(thrown) + .isInstanceOf(PreparationError.class) + .hasMessage("Fails to prepare an argument of the " // + + "testasyouthink.GivenFailuresTest$Parameter$Mutable type for the target method!") + .hasCauseInstanceOf(UnexpectedException.class); + verifyZeroInteractions(givenWhenThenDefinitionMock); + } + + @Test + public void should_fail_to_supply_a_third_argument() { + // WHEN + Throwable thrown = catchThrowable(() -> givenSutClass(SystemUnderTest.class) + .givenArgument(() -> "argument") + .andArgument(() -> 2) + .andArgument((CheckedSupplier) () -> { + throw new UnexpectedException(); + }) + .when(SystemUnderTest::voidMethodWithThreeParameters) + .then(() -> givenWhenThenDefinitionMock.thenTheActualResultIsInKeepingWithTheExpectedResult())); + + // THEN + LOGGER.debug("Stack trace", thrown); + assertThat(thrown) + .isInstanceOf(PreparationError.class) + .hasMessage("Fails to prepare an argument for the target method!") + .hasCauseInstanceOf(UnexpectedException.class); + verifyZeroInteractions(givenWhenThenDefinitionMock); + } + + @Test + public void should_fail_to_supply_a_third_argument_with_its_specification() { + // WHEN + Throwable thrown = catchThrowable(() -> givenSutClass(SystemUnderTest.class) + .givenArgument(() -> "argument") + .andArgument(() -> 2) + .andArgument("argument specification", (CheckedSupplier) () -> { + throw new UnexpectedException(); + }) + .when(SystemUnderTest::voidMethodWithThreeParameters) + .then(() -> givenWhenThenDefinitionMock.thenTheActualResultIsInKeepingWithTheExpectedResult())); + + // THEN + LOGGER.debug("Stack trace", thrown); + assertThat(thrown) + .isInstanceOf(PreparationError.class) + .hasMessage("Fails to prepare an argument for the target method!") + .hasCauseInstanceOf(UnexpectedException.class); + verifyZeroInteractions(givenWhenThenDefinitionMock); + } + + @Test + public void should_fail_to_prepare_a_third_argument_with_its_mutable_type() throws Throwable { + //GIVEN + class SystemUnderTestWithMutableParameter extends ParameterizedSystemUnderTest {} + SystemUnderTestWithMutableParameter sutWithMutableParameters = mock(SystemUnderTestWithMutableParameter.class); + + // WHEN + Throwable thrown = catchThrowable(() -> givenSut(sutWithMutableParameters) + .givenArgument(Mutable.class, mutable -> {}) + .andArgument(Mutable.class, mutable -> {}) + .andArgument(Mutable.class, mutable -> { + throw new UnexpectedException(); + }) + .whenSutRuns(ParameterizedSystemUnderTest::voidMethodWithThreeParameters) + .then(() -> givenWhenThenDefinitionMock.thenTheActualResultIsInKeepingWithTheExpectedResult())); + + // THEN + LOGGER.debug("Stack trace", thrown); + assertThat(thrown) + .isInstanceOf(PreparationError.class) + .hasMessage("Fails to prepare an argument of the " // + + "testasyouthink.GivenFailuresTest$Parameter$Mutable type for the target method!") + .hasCauseInstanceOf(UnexpectedException.class); + verifyZeroInteractions(givenWhenThenDefinitionMock); + } + + public static class SystemUnderTestFailingToBeInstantiated { + + public SystemUnderTestFailingToBeInstantiated() throws Exception { + throw new NullPointerException("Impossible to instantiate it!"); + } + + public void voidMethod() {} + } + + public static class Parameter { + + public static class Mutable { + + private int forDemonstration; + + public void setForDemonstration(int forDemonstration) { + this.forDemonstration = forDemonstration; + } + } + + public static class MutableButUninstantiable { + + public MutableButUninstantiable() throws InstantiationException { + throw new InstantiationException("Impossible to instantiate it!"); + } + } + } +} \ No newline at end of file diff --git a/test-as-you-think-core/src/test/java/testasyouthink/GivenWhenThenTest.java b/test-as-you-think-core/src/test/java/testasyouthink/GivenWhenThenTest.java index f950280..32f630e 100644 --- a/test-as-you-think-core/src/test/java/testasyouthink/GivenWhenThenTest.java +++ b/test-as-you-think-core/src/test/java/testasyouthink/GivenWhenThenTest.java @@ -23,18 +23,11 @@ package testasyouthink; import org.junit.After; -import org.junit.Before; import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import testasyouthink.fixture.GivenWhenThenDefinition; import testasyouthink.fixture.SystemUnderTest; -import testasyouthink.preparation.PreparationError; import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.catchThrowable; -import static org.easymock.EasyMock.replay; -import static org.easymock.EasyMock.reset; import static org.easymock.EasyMock.verify; import static testasyouthink.TestAsYouThink.givenSut; import static testasyouthink.TestAsYouThink.givenSutClass; @@ -42,16 +35,9 @@ public class GivenWhenThenTest { - private static final Logger LOGGER = LoggerFactory.getLogger(GivenWhenThenTest.class); private static final String EXPECTED_RESULT = "expected result"; private GivenWhenThenDefinition givenWhenThenDefinitionMock; - @Before - public void prepareFixtures() { - // GIVEN - givenWhenThenDefinitionMock = orderedSteps(); - } - @After public void verifyMocks() { // THEN @@ -60,6 +46,9 @@ public void verifyMocks() { @Test public void should_follow_the_given_when_then_full_sequence_given_a_non_void_method() { + // GIVEN + givenWhenThenDefinitionMock = orderedSteps(); + // WHEN givenSut(new SystemUnderTest(givenWhenThenDefinitionMock)) .given(() -> givenWhenThenDefinitionMock.givenAContextThatDefinesTheInitialStateOfTheSystem()) @@ -72,6 +61,9 @@ public void should_follow_the_given_when_then_full_sequence_given_a_non_void_met @Test public void should_follow_the_given_when_then_full_sequence_given_a_void_method() { + // GIVEN + givenWhenThenDefinitionMock = orderedSteps(); + // WHEN givenSut(new SystemUnderTest(givenWhenThenDefinitionMock)) .given(() -> givenWhenThenDefinitionMock.givenAContextThatDefinesTheInitialStateOfTheSystem()) @@ -81,6 +73,9 @@ public void should_follow_the_given_when_then_full_sequence_given_a_void_method( @Test public void should_follow_the_given_when_then_full_sequence_given_a_sut_class_to_be_instantiated() { + // GIVEN + givenWhenThenDefinitionMock = orderedSteps(); + // WHEN givenSutClass(SystemUnderTest.class) .given(sut -> { @@ -95,38 +90,49 @@ public void should_follow_the_given_when_then_full_sequence_given_a_sut_class_to } @Test - public void should_verify_expectations_on_the_sut_given_a_non_void_method() { + public void should_verify_expectations_on_the_sut_given_a_void_method() { + // GIVEN + givenWhenThenDefinitionMock = orderedSteps(); + // WHEN givenSutClass(SystemUnderTest.class) .given(sut -> { givenWhenThenDefinitionMock.givenAContextThatDefinesTheInitialStateOfTheSystem(); sut.setGivenWhenThenDefinition(givenWhenThenDefinitionMock); }) - .when(SystemUnderTest::nonVoidMethod) - .then((sut, result) -> { + .when(SystemUnderTest::voidMethod) + .then(sut -> { givenWhenThenDefinitionMock.thenTheActualResultIsInKeepingWithTheExpectedResult(); - assertThat(result).isEqualTo(EXPECTED_RESULT); assertThat(sut.getState()).isNotNull(); }); } @Test - public void should_verify_expectations_on_the_sut_given_a_void_method() { + public void should_verify_expectations_on_both_the_result_and_the_sut_given_a_non_void_method() { + // GIVEN + givenWhenThenDefinitionMock = orderedSteps(1, 2); + // WHEN givenSutClass(SystemUnderTest.class) .given(sut -> { givenWhenThenDefinitionMock.givenAContextThatDefinesTheInitialStateOfTheSystem(); sut.setGivenWhenThenDefinition(givenWhenThenDefinitionMock); }) - .when(SystemUnderTest::voidMethod) - .then(sut -> { + .when(SystemUnderTest::nonVoidMethod) + .then(result -> { givenWhenThenDefinitionMock.thenTheActualResultIsInKeepingWithTheExpectedResult(); - assertThat(sut.getState()).isNotNull(); + assertThat(result).isInstanceOf(String.class); + }, sut -> { + givenWhenThenDefinitionMock.thenTheActualResultIsInKeepingWithTheExpectedResult(); + assertThat(sut).isInstanceOf(SystemUnderTest.class); }); } @Test public void should_prepare_the_sut_with_a_given_step() { + // GIVEN + givenWhenThenDefinitionMock = orderedSteps(); + // WHEN givenSut(() -> { SystemUnderTest systemUnderTest = new SystemUnderTest(givenWhenThenDefinitionMock); @@ -139,6 +145,9 @@ public void should_prepare_the_sut_with_a_given_step() { @Test public void should_prepare_the_sut_with_a_given_step_given_a_sut_class_to_be_instantiated() { + // GIVEN + givenWhenThenDefinitionMock = orderedSteps(); + // WHEN givenSut(SystemUnderTest.class, sut -> { sut.setGivenWhenThenDefinition(givenWhenThenDefinitionMock); @@ -147,32 +156,4 @@ public void should_prepare_the_sut_with_a_given_step_given_a_sut_class_to_be_ins .when(SystemUnderTest::voidMethod) .then(() -> givenWhenThenDefinitionMock.thenTheActualResultIsInKeepingWithTheExpectedResult()); } - - @Test - public void should_fail_to_create_a_sut_instance() throws Throwable { - // GIVEN - reset(givenWhenThenDefinitionMock); - replay(givenWhenThenDefinitionMock); - - // WHEN - Throwable thrown = catchThrowable(() -> givenSutClass(SystemUnderTestFailingToBeInstantiated.class) - .when(SystemUnderTestFailingToBeInstantiated::voidMethod) - .then(() -> givenWhenThenDefinitionMock.thenTheActualResultIsInKeepingWithTheExpectedResult())); - - // THEN - LOGGER.debug("Stack trace", thrown); - assertThat(thrown) - .isInstanceOf(PreparationError.class) - .hasMessage("Fails to instantiate the system under test!") - .hasCauseInstanceOf(NullPointerException.class); - } - - public static class SystemUnderTestFailingToBeInstantiated { - - public SystemUnderTestFailingToBeInstantiated() throws Exception { - throw new NullPointerException("Impossible to instantiate it!"); - } - - void voidMethod() {} - } } diff --git a/test-as-you-think-core/src/test/java/testasyouthink/ThenAssertionErrorsTest.java b/test-as-you-think-core/src/test/java/testasyouthink/ThenAssertionErrorsTest.java new file mode 100644 index 0000000..793e279 --- /dev/null +++ b/test-as-you-think-core/src/test/java/testasyouthink/ThenAssertionErrorsTest.java @@ -0,0 +1,377 @@ +/*- + * #%L + * Test As You Think + * %% + * Copyright (C) 2017 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 + * . + * #L% + */ + +package testasyouthink; + +import org.junit.Test; +import testasyouthink.fixture.SystemUnderTest; +import testasyouthink.function.CheckedConsumer; + +import static java.util.Arrays.asList; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.catchThrowable; +import static testasyouthink.TestAsYouThink.givenSutClass; + +public class ThenAssertionErrorsTest { + + @Test + public void should_get_an_assertion_error_from_a_runnable_step_given_a_void_target_method() { + // WHEN + Throwable thrown = catchThrowable(() -> givenSutClass(SystemUnderTest.class) + .when(sut -> {}) + .then(() -> assertThat(true).isFalse())); + + // THEN + assertThat(thrown) + .isInstanceOf(AssertionError.class) + .hasNoCause(); + } + + @Test + public void should_get_an_assertion_error_from_another_runnable_step_given_a_void_target_method() { + // WHEN + Throwable thrown = catchThrowable(() -> givenSutClass(SystemUnderTest.class) + .when(sut -> {}) + .then(() -> {}) + .and(() -> assertThat(true).isFalse())); + + // THEN + assertThat(thrown) + .isInstanceOf(AssertionError.class) + .hasNoCause(); + } + + @Test + public void should_get_an_assertion_error_from_a_specified_runnable_step_given_a_void_target_method() { + // WHEN + Throwable thrown = catchThrowable(() -> givenSutClass(SystemUnderTest.class) + .when(sut -> {}) + .then("Expectations", () -> assertThat(true).isFalse())); + + // THEN + assertThat(thrown) + .isInstanceOf(AssertionError.class) + .hasNoCause(); + } + + @Test + public void should_get_an_assertion_error_from_another_specified_runnable_step_given_a_void_target_method() { + // WHEN + Throwable thrown = catchThrowable(() -> givenSutClass(SystemUnderTest.class) + .when(sut -> {}) + .then("An expectation", () -> {}) + .and("Another expectation", () -> assertThat(true).isFalse())); + + // THEN + assertThat(thrown) + .isInstanceOf(AssertionError.class) + .hasNoCause(); + } + + @Test + public void should_get_an_assertion_error_from_a_sut_consumer_step_given_a_void_target_method() { + // WHEN + Throwable thrown = catchThrowable(() -> givenSutClass(SystemUnderTest.class) + .when(sut -> {}) + .then(sut -> assertThat(true).isFalse())); + + // THEN + assertThat(thrown) + .isInstanceOf(AssertionError.class) + .hasNoCause(); + } + + @Test + public void should_get_an_assertion_error_from_another_sut_consumer_step_given_a_void_target_method() { + // WHEN + Throwable thrown = catchThrowable(() -> givenSutClass(SystemUnderTest.class) + .when(sut -> {}) + .then(sut -> {}) + .and(sut -> assertThat(true).isFalse())); + + // THEN + assertThat(thrown) + .isInstanceOf(AssertionError.class) + .hasNoCause(); + } + + @Test + public void should_get_an_assertion_error_from_a_sut_consumer_specified_step_given_a_void_target_method() { + // WHEN + Throwable thrown = catchThrowable(() -> givenSutClass(SystemUnderTest.class) + .when(sut -> {}) + .then("Expectations", sut -> assertThat(true).isFalse())); + + // THEN + assertThat(thrown) + .isInstanceOf(AssertionError.class) + .hasNoCause(); + } + + @Test + public void should_get_an_assertion_error_from_another_sut_consumer_specified_step_given_a_void_target_method() { + // WHEN + Throwable thrown = catchThrowable(() -> givenSutClass(SystemUnderTest.class) + .when(sut -> {}) + .then("An expectation", sut -> {}) + .and("Another expectation", sut -> assertThat(true).isFalse())); + + // THEN + assertThat(thrown) + .isInstanceOf(AssertionError.class) + .hasNoCause(); + } + + @Test + public void should_get_an_assertion_error_from_a_result_predicate_given_a_non_void_target_method() { + // WHEN + Throwable thrown = catchThrowable(() -> givenSutClass(SystemUnderTest.class) + .when(sut -> "result") + .then(result -> false)); + + // THEN + assertThat(thrown) + .isInstanceOf(AssertionError.class) + .hasNoCause(); + } + + @Test + public void should_get_an_assertion_error_from_another_result_predicate_given_a_non_void_target_method() { + // WHEN + Throwable thrown = catchThrowable(() -> givenSutClass(SystemUnderTest.class) + .when(sut -> "result") + .then(result -> true) + .and(result -> false)); + + // THEN + assertThat(thrown) + .isInstanceOf(AssertionError.class) + .hasNoCause(); + } + + @Test + public void should_get_an_assertion_error_from_a_boolean_supplier_given_a_void_target_method() { + // WHEN + Throwable thrown = catchThrowable(() -> givenSutClass(SystemUnderTest.class) + .when(sut -> {}) + .then(() -> false)); + + // THEN + assertThat(thrown) + .isInstanceOf(AssertionError.class) + .hasNoCause(); + } + + @Test + public void should_get_an_assertion_error_from_another_boolean_supplier_given_a_void_target_method() { + // WHEN + Throwable thrown = catchThrowable(() -> givenSutClass(SystemUnderTest.class) + .when(sut -> {}) + .then(() -> true) + .and(() -> false)); + + // THEN + assertThat(thrown) + .isInstanceOf(AssertionError.class) + .hasNoCause(); + } + + @Test + public void should_get_an_assertion_error_from_result_predicates_given_a_non_void_target_method() { + // WHEN + Throwable thrown = catchThrowable(() -> givenSutClass(SystemUnderTest.class) + .when(sut -> "result") + .then(asList(result -> true, result -> false))); + + // THEN + assertThat(thrown) + .isInstanceOf(AssertionError.class) + .hasNoCause(); + } + + @Test + public void + should_get_an_assertion_error_from_result_and_sut_predicates_because_of_the_result_given_a_non_void_target_method + () { + // WHEN + Throwable thrown = catchThrowable(() -> givenSutClass(SystemUnderTest.class) + .when(sut -> "result") + .then(result -> false, sut -> true)); + + // THEN + assertThat(thrown) + .isInstanceOf(AssertionError.class) + .hasNoCause(); + } + + @Test + public void + should_get_an_assertion_error_from_result_and_sut_predicates_because_of_the_sut_given_a_non_void_target_method() { + // WHEN + Throwable thrown = catchThrowable(() -> givenSutClass(SystemUnderTest.class) + .when(sut -> "result") + .then(result -> true, sut -> false)); + + // THEN + assertThat(thrown) + .isInstanceOf(AssertionError.class) + .hasNoCause(); + } + + @Test + public void should_get_an_assertion_error_from_a_result_consumer_given_a_non_void_target_method() { + // WHEN + Throwable thrown = catchThrowable(() -> givenSutClass(SystemUnderTest.class) + .when(sut -> "result") + .then((CheckedConsumer) result -> assertThat(true).isFalse())); + + // THEN + assertThat(thrown) + .isInstanceOf(AssertionError.class) + .hasNoCause(); + } + + @Test + public void should_get_an_assertion_error_from_another_result_consumer_given_a_non_void_target_method() { + // WHEN + Throwable thrown = catchThrowable(() -> givenSutClass(SystemUnderTest.class) + .when(sut -> "result") + .then(result -> {}) + .and((CheckedConsumer) result -> assertThat(true).isFalse())); + + // THEN + assertThat(thrown) + .isInstanceOf(AssertionError.class) + .hasNoCause(); + } + + @Test + public void should_get_an_assertion_error_from_a_specified_result_consumer_given_a_non_void_target_method() { + // WHEN + Throwable thrown = catchThrowable(() -> givenSutClass(SystemUnderTest.class) + .when(sut -> "result") + .then("Expectations", result -> assertThat(true).isFalse())); + + // THEN + assertThat(thrown) + .isInstanceOf(AssertionError.class) + .hasNoCause(); + } + + @Test + public void should_get_an_assertion_error_from_another_specified_result_consumer_given_a_non_void_target_method() { + // WHEN + Throwable thrown = catchThrowable(() -> givenSutClass(SystemUnderTest.class) + .when(sut -> "result") + .then(result -> {}) + .and("Expectations", result -> assertThat(true).isFalse())); + + // THEN + assertThat(thrown) + .isInstanceOf(AssertionError.class) + .hasNoCause(); + } + + @Test + public void + should_get_an_assertion_error_from_result_and_sut_consumers_because_of_the_result_given_a_non_void_target_method() { + // WHEN + Throwable thrown = catchThrowable(() -> givenSutClass(SystemUnderTest.class) + .when(sut -> "result") + .then(result -> false, sut -> true)); + + // THEN + assertThat(thrown) + .isInstanceOf(AssertionError.class) + .hasNoCause(); + } + + @Test + public void + should_get_an_assertion_error_from_result_and_sut_consumers_because_of_the_sut_given_a_non_void_target_method() { + // WHEN + Throwable thrown = catchThrowable(() -> givenSutClass(SystemUnderTest.class) + .when(sut -> "result") + .then(result -> true, sut -> false)); + + // THEN + assertThat(thrown) + .isInstanceOf(AssertionError.class) + .hasNoCause(); + } + + @Test + public void should_get_an_assertion_error_from_a_runnable_step_given_a_non_void_target_method() { + // WHEN + Throwable thrown = catchThrowable(() -> givenSutClass(SystemUnderTest.class) + .when(sut -> "result") + .then(() -> assertThat(true).isFalse())); + + // THEN + assertThat(thrown) + .isInstanceOf(AssertionError.class) + .hasNoCause(); + } + + @Test + public void should_get_an_assertion_error_from_another_runnable_step_given_a_non_void_target_method() { + // WHEN + Throwable thrown = catchThrowable(() -> givenSutClass(SystemUnderTest.class) + .when(sut -> "result") + .then(() -> {}) + .and(() -> assertThat(true).isFalse())); + + // THEN + assertThat(thrown) + .isInstanceOf(AssertionError.class) + .hasNoCause(); + } + + @Test + public void + should_get_an_assertion_error_from_a_runnable_step_with_its_specification_given_a_non_void_target_method() { + // WHEN + Throwable thrown = catchThrowable(() -> givenSutClass(SystemUnderTest.class) + .when(sut -> "result") + .then("Expectations", () -> assertThat(true).isFalse())); + + // THEN + assertThat(thrown) + .isInstanceOf(AssertionError.class) + .hasNoCause(); + } + + @Test + public void + should_get_an_assertion_error_from_another_runnable_step_with_its_specification_given_a_non_void_target_method() { + // WHEN + Throwable thrown = catchThrowable(() -> givenSutClass(SystemUnderTest.class) + .when(sut -> "result") + .then("Expectations", () -> {}) + .and("Expectations", () -> assertThat(true).isFalse())); + + // THEN + assertThat(thrown) + .isInstanceOf(AssertionError.class) + .hasNoCause(); + } +} diff --git a/test-as-you-think-core/src/test/java/testasyouthink/ThenFailuresTest.java b/test-as-you-think-core/src/test/java/testasyouthink/ThenExpectedFailuresTest.java similarity index 99% rename from test-as-you-think-core/src/test/java/testasyouthink/ThenFailuresTest.java rename to test-as-you-think-core/src/test/java/testasyouthink/ThenExpectedFailuresTest.java index af1eacd..fabb2fa 100644 --- a/test-as-you-think-core/src/test/java/testasyouthink/ThenFailuresTest.java +++ b/test-as-you-think-core/src/test/java/testasyouthink/ThenExpectedFailuresTest.java @@ -39,9 +39,9 @@ import static org.easymock.EasyMock.verify; import static testasyouthink.TestAsYouThink.givenSut; -public class ThenFailuresTest { +public class ThenExpectedFailuresTest { - private static final Logger LOGGER = LoggerFactory.getLogger(ThenFailuresTest.class); + private static final Logger LOGGER = LoggerFactory.getLogger(ThenExpectedFailuresTest.class); private static final String EXPECTED_MESSAGE = "expected message"; private static final String UNEXPECTED_MESSAGE = "unexpected message"; private static final String EXPECTED_CAUSE_MESSAGE = "expected cause message"; diff --git a/test-as-you-think-core/src/test/java/testasyouthink/ThenNoFailureTest.java b/test-as-you-think-core/src/test/java/testasyouthink/ThenNoFailureTest.java new file mode 100644 index 0000000..0c62900 --- /dev/null +++ b/test-as-you-think-core/src/test/java/testasyouthink/ThenNoFailureTest.java @@ -0,0 +1,66 @@ +/*- + * #%L + * Test As You Think + * %% + * Copyright (C) 2017 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 + * . + * #L% + */ + +package testasyouthink; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mockito; +import testasyouthink.fixture.GivenWhenThenDefinition; +import testasyouthink.fixture.SystemUnderTest; + +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; +import static testasyouthink.TestAsYouThink.givenSutClass; +import static testasyouthink.TestAsYouThink.when; + +public class ThenNoFailureTest { + + private GivenWhenThenDefinition gwtMock; + + @Before + public void prepareFixtures() { + gwtMock = Mockito.mock(GivenWhenThenDefinition.class); + } + + @After + public void verifyMocks() { + // THEN + verify(gwtMock).whenAnEventHappensInRelationToAnActionOfTheConsumer(); + verifyNoMoreInteractions(gwtMock); + } + + @Test + public void should_verify_no_failure_happened_during_the_execution_stage() { + // WHEN + givenSutClass(SystemUnderTest.class) + .when(sut -> { gwtMock.whenAnEventHappensInRelationToAnActionOfTheConsumer(); }) + .thenItSucceeds(); + } + + @Test + public void should_verify_no_failure_happened_during_the_execution_stage_while_starting_with_the_event() { + // WHEN + when(() -> gwtMock.whenAnEventHappensInRelationToAnActionOfTheConsumer()).thenItSucceeds(); + } +} diff --git a/test-as-you-think-core/src/test/java/testasyouthink/ThenPredicateTest.java b/test-as-you-think-core/src/test/java/testasyouthink/ThenPredicateTest.java index 9b7d8d0..c125a57 100644 --- a/test-as-you-think-core/src/test/java/testasyouthink/ThenPredicateTest.java +++ b/test-as-you-think-core/src/test/java/testasyouthink/ThenPredicateTest.java @@ -23,7 +23,6 @@ package testasyouthink; import org.junit.After; -import org.junit.ComparisonFailure; import org.junit.Test; import testasyouthink.fixture.GivenWhenThenDefinition; import testasyouthink.fixture.SystemUnderTest; @@ -69,46 +68,6 @@ public void should_receive_a_then_step_as_a_result_predicate_given_a_non_void_me }); } - @Test(expected = ComparisonFailure.class) - public void should_receive_a_failing_then_step_as_a_predicate_on_the_result_given_a_non_void_method() { - // GIVEN - givenWhenThenDefinitionMock = orderedSteps(1, 1); - - // WHEN - givenSutClass(SystemUnderTest.class) - .given(sut -> { - givenWhenThenDefinitionMock.givenAContextThatDefinesTheInitialStateOfTheSystem(); - sut.setGivenWhenThenDefinition(givenWhenThenDefinitionMock); - }) - .when(SystemUnderTest::nonVoidMethod) - .then(result -> { - givenWhenThenDefinitionMock.thenTheActualResultIsInKeepingWithTheExpectedResult(); - return false; - }); - } - - @Test(expected = ComparisonFailure.class) - public void should_receive_a_failing_andthen_step_as_a_predicate_on_the_result_given_a_non_void_method() { - // GIVEN - givenWhenThenDefinitionMock = orderedSteps(1, 2); - - // WHEN - givenSutClass(SystemUnderTest.class) - .given(sut -> { - givenWhenThenDefinitionMock.givenAContextThatDefinesTheInitialStateOfTheSystem(); - sut.setGivenWhenThenDefinition(givenWhenThenDefinitionMock); - }) - .when(SystemUnderTest::nonVoidMethod) - .then(result -> { - givenWhenThenDefinitionMock.thenTheActualResultIsInKeepingWithTheExpectedResult(); - return true; - }) - .and(result -> { - givenWhenThenDefinitionMock.thenTheActualResultIsInKeepingWithTheExpectedResult(); - return false; - }); - } - @Test public void should_receive_a_then_step_as_a_predicate_given_a_void_method() { // GIVEN @@ -135,46 +94,6 @@ public void should_receive_a_then_step_as_a_predicate_given_a_void_method() { }); } - @Test(expected = ComparisonFailure.class) - public void should_receive_a_failing_then_step_as_a_predicate_given_a_void_method() { - // GIVEN - givenWhenThenDefinitionMock = orderedSteps(1, 1); - - // WHEN - givenSutClass(SystemUnderTest.class) - .given(sut -> { - givenWhenThenDefinitionMock.givenAContextThatDefinesTheInitialStateOfTheSystem(); - sut.setGivenWhenThenDefinition(givenWhenThenDefinitionMock); - }) - .when(SystemUnderTest::voidMethod) - .then(() -> { - givenWhenThenDefinitionMock.thenTheActualResultIsInKeepingWithTheExpectedResult(); - return false; - }); - } - - @Test(expected = ComparisonFailure.class) - public void should_receive_failing_and_then_steps_as_predicates_given_a_void_method() { - // GIVEN - givenWhenThenDefinitionMock = orderedSteps(1, 2); - - // WHEN - givenSutClass(SystemUnderTest.class) - .given(sut -> { - givenWhenThenDefinitionMock.givenAContextThatDefinesTheInitialStateOfTheSystem(); - sut.setGivenWhenThenDefinition(givenWhenThenDefinitionMock); - }) - .when(SystemUnderTest::voidMethod) - .then(() -> { - givenWhenThenDefinitionMock.thenTheActualResultIsInKeepingWithTheExpectedResult(); - return true; - }) - .and(() -> { - givenWhenThenDefinitionMock.thenTheActualResultIsInKeepingWithTheExpectedResult(); - return false; - }); - } - @Test public void should_receive_the_then_steps_as_predicates_on_the_result_given_a_non_void_method() { // GIVEN @@ -196,65 +115,6 @@ public void should_receive_the_then_steps_as_predicates_on_the_result_given_a_no })); } - @Test(expected = ComparisonFailure.class) - public void - should_receive_the_then_steps_as_predicates_on_the_result_given_a_non_void_method_and_a_failing_then_step() { - // GIVEN - givenWhenThenDefinitionMock = orderedSteps(1, 2); - - // WHEN - givenSutClass(SystemUnderTest.class) - .given(sut -> { - givenWhenThenDefinitionMock.givenAContextThatDefinesTheInitialStateOfTheSystem(); - sut.setGivenWhenThenDefinition(givenWhenThenDefinitionMock); - }) - .when(SystemUnderTest::nonVoidMethod) - .then(asList(result -> { - givenWhenThenDefinitionMock.thenTheActualResultIsInKeepingWithTheExpectedResult(); - return true; - }, result -> { - givenWhenThenDefinitionMock.thenTheActualResultIsInKeepingWithTheExpectedResult(); - return false; - })); - } - - @Test - public void should_receive_a_then_step_as_a_predicate_on_the_system_and_the_result_given_a_non_void_method() { - // GIVEN - givenWhenThenDefinitionMock = orderedSteps(1, 1); - - // WHEN - givenSutClass(SystemUnderTest.class) - .given(sut -> { - givenWhenThenDefinitionMock.givenAContextThatDefinesTheInitialStateOfTheSystem(); - sut.setGivenWhenThenDefinition(givenWhenThenDefinitionMock); - }) - .when(SystemUnderTest::nonVoidMethod) - .then((sut, result) -> { - givenWhenThenDefinitionMock.thenTheActualResultIsInKeepingWithTheExpectedResult(); - return "expected result" .equals(result) && sut != null; - }); - } - - @Test(expected = ComparisonFailure.class) - public void - should_receive_a_failing_then_step_as_a_predicate_on_the_system_and_the_result_given_a_non_void_method() { - // GIVEN - givenWhenThenDefinitionMock = orderedSteps(1, 1); - - // WHEN - givenSutClass(SystemUnderTest.class) - .given(sut -> { - givenWhenThenDefinitionMock.givenAContextThatDefinesTheInitialStateOfTheSystem(); - sut.setGivenWhenThenDefinition(givenWhenThenDefinitionMock); - }) - .when(SystemUnderTest::nonVoidMethod) - .then((sut, result) -> { - givenWhenThenDefinitionMock.thenTheActualResultIsInKeepingWithTheExpectedResult(); - return false; - }); - } - @Test public void should_receive_the_then_steps_as_predicates_on_the_system_or_the_result_given_a_non_void_method() { // GIVEN @@ -275,48 +135,4 @@ public void should_receive_the_then_steps_as_predicates_on_the_system_or_the_res return true; }); } - - @Test(expected = ComparisonFailure.class) - public void - should_receive_the_then_steps_as_predicates_on_the_system_or_the_result_given_a_non_void_method_and_a_failing_then_step_on_the_result() { - // GIVEN - givenWhenThenDefinitionMock = orderedSteps(1, 1); - - // THEN - givenSutClass(SystemUnderTest.class) - .given(sut -> { - givenWhenThenDefinitionMock.givenAContextThatDefinesTheInitialStateOfTheSystem(); - sut.setGivenWhenThenDefinition(givenWhenThenDefinitionMock); - }) - .when(SystemUnderTest::nonVoidMethod) - .then(result -> { - givenWhenThenDefinitionMock.thenTheActualResultIsInKeepingWithTheExpectedResult(); - return false; - }, sut -> { - givenWhenThenDefinitionMock.thenTheActualResultIsInKeepingWithTheExpectedResult(); - return true; - }); - } - - @Test(expected = ComparisonFailure.class) - public void - should_receive_the_then_steps_as_predicates_on_the_sut_or_the_result_given_a_non_void_method_and_a_failing_then_step_on_the_sut() { - // GIVEN - givenWhenThenDefinitionMock = orderedSteps(1, 2); - - // THEN - givenSutClass(SystemUnderTest.class) - .given(sut -> { - givenWhenThenDefinitionMock.givenAContextThatDefinesTheInitialStateOfTheSystem(); - sut.setGivenWhenThenDefinition(givenWhenThenDefinitionMock); - }) - .when(SystemUnderTest::nonVoidMethod) - .then(result -> { - givenWhenThenDefinitionMock.thenTheActualResultIsInKeepingWithTheExpectedResult(); - return true; - }, sut -> { - givenWhenThenDefinitionMock.thenTheActualResultIsInKeepingWithTheExpectedResult(); - return false; - }); - } } diff --git a/test-as-you-think-core/src/test/java/testasyouthink/ThenSutRepliesWithinTimeLimitTest.java b/test-as-you-think-core/src/test/java/testasyouthink/ThenSutRepliesWithinTimeLimitTest.java index fe6a9f9..f49bdc1 100644 --- a/test-as-you-think-core/src/test/java/testasyouthink/ThenSutRepliesWithinTimeLimitTest.java +++ b/test-as-you-think-core/src/test/java/testasyouthink/ThenSutRepliesWithinTimeLimitTest.java @@ -22,7 +22,9 @@ package testasyouthink; +import org.junit.Before; import org.junit.Test; +import testasyouthink.fixture.GivenWhenThenDefinition; import testasyouthink.fixture.SystemUnderTest; import testasyouthink.function.CheckedConsumer; @@ -32,13 +34,112 @@ import static java.lang.Thread.currentThread; import static java.lang.Thread.sleep; +import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; import static testasyouthink.TestAsYouThink.givenSutClass; public class ThenSutRepliesWithinTimeLimitTest { + private GivenWhenThenDefinition gwtDefinition; + + @Before + public void prepareFixtures() { + gwtDefinition = mock(GivenWhenThenDefinition.class); + } + + @Test + public void should_reply_within_a_time_limit_given_a_void_method() { + // WHEN + givenSutClass(SystemUnderTest.class) + .given(() -> { + gwtDefinition.givenAContextThatDefinesTheInitialStateOfTheSystem(); + sleep(50); + }) + .whenSutRuns(sut -> gwtDefinition.whenAnEventHappensInRelationToAnActionOfTheConsumer()) + .thenSutRepliesWithin(49) + .and(() -> gwtDefinition.thenTheActualResultIsInKeepingWithTheExpectedResult()); + + // THEN + verify(gwtDefinition).givenAContextThatDefinesTheInitialStateOfTheSystem(); + verify(gwtDefinition).whenAnEventHappensInRelationToAnActionOfTheConsumer(); + verify(gwtDefinition).thenTheActualResultIsInKeepingWithTheExpectedResult(); + verifyNoMoreInteractions(gwtDefinition); + } + + @Test + public void should_reply_within_a_time_limit_given_a_method_with_a_parameter() { + // WHEN + givenSutClass(SystemUnderTest.class) + .givenArgument(() -> { + gwtDefinition.givenAContextThatDefinesTheInitialStateOfTheSystem(); + sleep(50); + return "argument"; + }) + .when((sut, argument) -> { + gwtDefinition.whenAnEventHappensInRelationToAnActionOfTheConsumer(); + }) + .thenSutRepliesWithin(49) + .and(() -> gwtDefinition.thenTheActualResultIsInKeepingWithTheExpectedResult()); + + // THEN + verify(gwtDefinition).givenAContextThatDefinesTheInitialStateOfTheSystem(); + verify(gwtDefinition).whenAnEventHappensInRelationToAnActionOfTheConsumer(); + verify(gwtDefinition).thenTheActualResultIsInKeepingWithTheExpectedResult(); + verifyNoMoreInteractions(gwtDefinition); + } + + @Test + public void should_reply_within_a_time_limit_given_a_method_with_a_mutable_parameter() { + // WHEN + givenSutClass(SystemUnderTest.class) + .givenArgument(StringBuilder.class, mutable -> { + gwtDefinition.givenAContextThatDefinesTheInitialStateOfTheSystem(); + mutable.append("argument"); + sleep(50); + }) + .when((sut, argument) -> { + gwtDefinition.whenAnEventHappensInRelationToAnActionOfTheConsumer(); + }) + .thenSutRepliesWithin(49) + .and(() -> gwtDefinition.thenTheActualResultIsInKeepingWithTheExpectedResult()); + + // THEN + verify(gwtDefinition).givenAContextThatDefinesTheInitialStateOfTheSystem(); + verify(gwtDefinition).whenAnEventHappensInRelationToAnActionOfTheConsumer(); + verify(gwtDefinition).thenTheActualResultIsInKeepingWithTheExpectedResult(); + verifyNoMoreInteractions(gwtDefinition); + } + + @Test + public void should_reply_within_a_time_limit_given_a_non_void_method() { + // WHEN + givenSutClass(SystemUnderTest.class) + .given(() -> { + gwtDefinition.givenAContextThatDefinesTheInitialStateOfTheSystem(); + sleep(50); + }) + .when(sut -> { + gwtDefinition.whenAnEventHappensInRelationToAnActionOfTheConsumer(); + return "expected result"; + }) + .thenSutRepliesWithin(49) + .and(result -> { + assertThat(result).isEqualTo("expected result"); + gwtDefinition.thenTheActualResultIsInKeepingWithTheExpectedResult(); + }); + + // THEN + verify(gwtDefinition).givenAContextThatDefinesTheInitialStateOfTheSystem(); + verify(gwtDefinition).whenAnEventHappensInRelationToAnActionOfTheConsumer(); + verify(gwtDefinition).thenTheActualResultIsInKeepingWithTheExpectedResult(); + verifyNoMoreInteractions(gwtDefinition); + } + @Test - public void should_fail_given_a_time_limit_for_a_void_method() { + public void should_fail_to_reply_within_a_time_limit_given_a_void_method() { assertThatThrownBy(() -> givenSutClass(SystemUnderTest.class) .when(sut -> { sleep(1000); @@ -50,7 +151,7 @@ public void should_fail_given_a_time_limit_for_a_void_method() { } @Test - public void should_fail_given_a_duration_limit_for_a_void_method() { + public void should_fail_to_reply_within_a_duration_limit_given_a_void_method() { assertThatThrownBy(() -> givenSutClass(SystemUnderTest.class) .when(sut -> { sleep(1000); @@ -62,7 +163,7 @@ public void should_fail_given_a_duration_limit_for_a_void_method() { } @Test - public void should_fail_when_the_current_thread_was_interrupted_while_waiting_given_a_void_method() { + public void should_fail_to_execute_when_the_current_thread_was_interrupted_while_waiting_given_a_void_method() { assertThatThrownBy(() -> givenSutClass(SystemUnderTest.class) .when(sut -> { currentThread() @@ -77,7 +178,7 @@ public void should_fail_when_the_current_thread_was_interrupted_while_waiting_gi } @Test - public void should_fail_when_the_computation_throws_an_exception_given_a_void_method() { + public void should_fail_to_execute_when_the_computation_throws_an_exception_given_a_void_method() { assertThatThrownBy(() -> givenSutClass(SystemUnderTest.class) .when((CheckedConsumer) sut -> { throw new Exception("unexpected exception"); @@ -89,7 +190,7 @@ public void should_fail_when_the_computation_throws_an_exception_given_a_void_me } @Test - public void should_fail_given_a_time_limit_for_a_non_void_method() { + public void should_fail_to_reply_within_a_time_limit_given_a_non_void_method() { assertThatThrownBy(() -> givenSutClass(SystemUnderTest.class) .when(sut -> { sleep(1000); @@ -102,7 +203,7 @@ public void should_fail_given_a_time_limit_for_a_non_void_method() { } @Test - public void should_fail_given_a_duration_limit_for_a_non_void_method() { + public void should_fail_to_reply_within_a_duration_limit_given_a_non_void_method() { assertThatThrownBy(() -> givenSutClass(SystemUnderTest.class) .when(sut -> { sleep(1000); diff --git a/test-as-you-think-core/src/test/java/testasyouthink/ThenUnexpectedFailuresTest.java b/test-as-you-think-core/src/test/java/testasyouthink/ThenUnexpectedFailuresTest.java new file mode 100644 index 0000000..f162135 --- /dev/null +++ b/test-as-you-think-core/src/test/java/testasyouthink/ThenUnexpectedFailuresTest.java @@ -0,0 +1,476 @@ +/*- + * #%L + * Test As You Think + * %% + * Copyright (C) 2017 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 + * . + * #L% + */ + +package testasyouthink; + +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import testasyouthink.fixture.SystemUnderTest; +import testasyouthink.fixture.UnexpectedException; +import testasyouthink.function.CheckedConsumer; +import testasyouthink.function.CheckedPredicate; +import testasyouthink.function.CheckedRunnable; +import testasyouthink.verification.VerificationError; + +import static java.util.Arrays.asList; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.catchThrowable; +import static testasyouthink.TestAsYouThink.givenSutClass; +import static testasyouthink.TestAsYouThink.when; + +public class ThenUnexpectedFailuresTest { + + private static final Logger LOGGER = LoggerFactory.getLogger(ThenUnexpectedFailuresTest.class); + + @Test + public void should_fail_to_run_a_verification_step_given_a_void_target_method() { + // WHEN + Throwable thrown = catchThrowable(() -> givenSutClass(SystemUnderTest.class) + .when(sut -> {}) + .then((CheckedRunnable) () -> { + throw new UnexpectedException(); + })); + + // THEN + LOGGER.debug("Stack trace", thrown); + assertThat(thrown) + .isInstanceOf(VerificationError.class) + .hasMessage("Fails to verify expectations!") + .hasCauseInstanceOf(UnexpectedException.class); + } + + @Test + public void should_fail_to_run_another_verification_step_given_a_void_target_method() { + // WHEN + Throwable thrown = catchThrowable(() -> givenSutClass(SystemUnderTest.class) + .when(sut -> {}) + .then(() -> {}) + .and((CheckedRunnable) () -> { + throw new UnexpectedException(); + })); + + // THEN + LOGGER.debug("Stack trace", thrown); + assertThat(thrown) + .isInstanceOf(VerificationError.class) + .hasMessage("Fails to verify expectations!") + .hasCauseInstanceOf(UnexpectedException.class); + } + + @Test + public void should_fail_to_run_a_verification_step_with_its_specification_given_a_void_target_method() { + // WHEN + Throwable thrown = catchThrowable(() -> givenSutClass(SystemUnderTest.class) + .when(sut -> {}) + .then("Expectations", () -> { + throw new UnexpectedException(); + })); + + // THEN + LOGGER.debug("Stack trace", thrown); + assertThat(thrown) + .isInstanceOf(VerificationError.class) + .hasMessage("Fails to verify expectations!") + .hasCauseInstanceOf(UnexpectedException.class); + } + + @Test + public void should_fail_to_run_another_verification_step_with_its_specification_given_a_void_target_method() { + // WHEN + Throwable thrown = catchThrowable(() -> givenSutClass(SystemUnderTest.class) + .when(sut -> {}) + .then("An expectation", () -> {}) + .and("Another expectation", () -> { + throw new UnexpectedException(); + })); + + // THEN + LOGGER.debug("Stack trace", thrown); + assertThat(thrown) + .isInstanceOf(VerificationError.class) + .hasMessage("Fails to verify expectations!") + .hasCauseInstanceOf(UnexpectedException.class); + } + + @Test + public void should_fail_to_verify_a_sut_expectation_given_a_void_target_method() { + // WHEN + Throwable thrown = catchThrowable(() -> givenSutClass(SystemUnderTest.class) + .when(sut -> {}) + .then(sut -> { + throw new UnexpectedException(); + })); + + // THEN + LOGGER.debug("Stack trace", thrown); + assertThat(thrown) + .isInstanceOf(VerificationError.class) + .hasMessage("Fails to verify the expectations of the system under test!") + .hasCauseInstanceOf(UnexpectedException.class); + } + + @Test + public void should_fail_to_verify_another_sut_expectation_given_a_void_target_method() { + // WHEN + Throwable thrown = catchThrowable(() -> givenSutClass(SystemUnderTest.class) + .when(sut -> {}) + .then(sut -> {}) + .and(sut -> { + throw new UnexpectedException(); + })); + + // THEN + LOGGER.debug("Stack trace", thrown); + assertThat(thrown) + .isInstanceOf(VerificationError.class) + .hasMessage("Fails to verify the expectations of the system under test!") + .hasCauseInstanceOf(UnexpectedException.class); + } + + @Test + public void should_fail_to_verify_a_sut_specified_expectation_given_a_void_target_method() { + // WHEN + Throwable thrown = catchThrowable(() -> givenSutClass(SystemUnderTest.class) + .when(sut -> {}) + .then("Expectations", sut -> { + throw new UnexpectedException(); + })); + + // THEN + LOGGER.debug("Stack trace", thrown); + assertThat(thrown) + .isInstanceOf(VerificationError.class) + .hasMessage("Fails to verify the expectations of the system under test!") + .hasCauseInstanceOf(UnexpectedException.class); + } + + @Test + public void should_fail_to_verify_another_sut_specified_expectation_given_a_void_target_method() { + // WHEN + Throwable thrown = catchThrowable(() -> givenSutClass(SystemUnderTest.class) + .when(sut -> {}) + .then("An expectation", sut -> {}) + .and("Another expectation", sut -> { + throw new UnexpectedException(); + })); + + // THEN + LOGGER.debug("Stack trace", thrown); + assertThat(thrown) + .isInstanceOf(VerificationError.class) + .hasMessage("Fails to verify the expectations of the system under test!") + .hasCauseInstanceOf(UnexpectedException.class); + } + + @Test + public void + should_fail_to_verify_the_result_and_sut_expectations_because_of_the_result_given_a_non_void_target_method() { + // WHEN + Throwable thrown = catchThrowable(() -> givenSutClass(SystemUnderTest.class) + .when(sut -> "result") + .then(result -> { + throw new UnexpectedException(); + }, sut -> true)); + + // THEN + assertThat(thrown) + .isInstanceOf(VerificationError.class) + .hasMessage("Fails to verify the result expectations!") + .hasCauseInstanceOf(UnexpectedException.class); + } + + @Test + public void + should_fail_to_verify_the_result_and_sut_expectations_because_of_the_sut_given_a_non_void_target_method() { + // WHEN + Throwable thrown = catchThrowable(() -> givenSutClass(SystemUnderTest.class) + .when(sut -> "result") + .then(result -> true, sut -> { + throw new UnexpectedException(); + })); + + // THEN + assertThat(thrown) + .isInstanceOf(VerificationError.class) + .hasMessage("Fails to verify the expectations of the system under test!") + .hasCauseInstanceOf(UnexpectedException.class); + } + + @Test + public void should_fail_to_apply_a_condition_given_a_void_target_method() { + // WHEN + Throwable thrown = catchThrowable(() -> givenSutClass(SystemUnderTest.class) + .when(sut -> {}) + .then(() -> { + throw new UnexpectedException(); + })); + + // THEN + LOGGER.debug("Stack trace", thrown); + assertThat(thrown) + .isInstanceOf(VerificationError.class) + .hasMessage("Fails to verify expectations!") + .hasCauseInstanceOf(UnexpectedException.class); + } + + @Test + public void should_fail_to_apply_another_condition_given_a_void_target_method() { + // WHEN + Throwable thrown = catchThrowable(() -> givenSutClass(SystemUnderTest.class) + .when(sut -> {}) + .then(() -> true) + .and(() -> { + throw new UnexpectedException(); + })); + + // THEN + LOGGER.debug("Stack trace", thrown); + assertThat(thrown) + .isInstanceOf(VerificationError.class) + .hasMessage("Fails to verify expectations!") + .hasCauseInstanceOf(UnexpectedException.class); + } + + @Test + public void should_fail_to_verify_a_result_expectation_given_a_non_void_target_method() { + // WHEN + Throwable thrown = catchThrowable(() -> givenSutClass(SystemUnderTest.class) + .when(sut -> "result") + .then((CheckedConsumer) result -> { + throw new UnexpectedException(); + })); + + // THEN + LOGGER.debug("Stack trace", thrown); + assertThat(thrown) + .isInstanceOf(VerificationError.class) + .hasMessage("Fails to verify the result expectations!") + .hasCauseInstanceOf(UnexpectedException.class); + } + + @Test + public void should_fail_to_verify_a_result_expectation_with_its_specification_given_a_non_void_target_method() { + // WHEN + Throwable thrown = catchThrowable(() -> givenSutClass(SystemUnderTest.class) + .when(sut -> "result") + .then("Expectations", result -> { + throw new UnexpectedException(); + })); + + // THEN + LOGGER.debug("Stack trace", thrown); + assertThat(thrown) + .isInstanceOf(VerificationError.class) + .hasMessage("Fails to verify the result expectations!") + .hasCauseInstanceOf(UnexpectedException.class); + } + + @Test + public void + should_fail_to_verify_another_result_expectation_with_its_specification_given_a_non_void_target_method() { + // WHEN + Throwable thrown = catchThrowable(() -> givenSutClass(SystemUnderTest.class) + .when(sut -> "result") + .then(result -> {}) + .and("Expectations", result -> { + throw new UnexpectedException(); + })); + + // THEN + LOGGER.debug("Stack trace", thrown); + assertThat(thrown) + .isInstanceOf(VerificationError.class) + .hasMessage("Fails to verify the result expectations!") + .hasCauseInstanceOf(UnexpectedException.class); + } + + @Test + public void should_fail_to_run_a_verification_step_given_a_non_void_target_method() { + // WHEN + Throwable thrown = catchThrowable(() -> givenSutClass(SystemUnderTest.class) + .when(sut -> "result") + .then(() -> { + throw new UnexpectedException(); + })); + + // THEN + LOGGER.debug("Stack trace", thrown); + assertThat(thrown) + .isInstanceOf(VerificationError.class) + .hasMessage("Fails to verify expectations!") + .hasCauseInstanceOf(UnexpectedException.class); + } + + @Test + public void should_fail_to_run_another_verification_step_given_a_non_void_target_method() { + // WHEN + Throwable thrown = catchThrowable(() -> givenSutClass(SystemUnderTest.class) + .when(sut -> "result") + .then(() -> {}) + .and(() -> { + throw new UnexpectedException(); + })); + + // THEN + LOGGER.debug("Stack trace", thrown); + assertThat(thrown) + .isInstanceOf(VerificationError.class) + .hasMessage("Fails to verify expectations!") + .hasCauseInstanceOf(UnexpectedException.class); + } + + @Test + public void should_fail_to_run_a_verification_step_with_its_specification_given_a_non_void_target_method() { + // WHEN + Throwable thrown = catchThrowable(() -> givenSutClass(SystemUnderTest.class) + .when(sut -> "result") + .then("Expectations", () -> { + throw new UnexpectedException(); + })); + + // THEN + LOGGER.debug("Stack trace", thrown); + assertThat(thrown) + .isInstanceOf(VerificationError.class) + .hasMessage("Fails to verify expectations!") + .hasCauseInstanceOf(UnexpectedException.class); + } + + @Test + public void should_fail_to_run_another_verification_step_with_its_specification_given_a_non_void_target_method() { + // WHEN + Throwable thrown = catchThrowable(() -> givenSutClass(SystemUnderTest.class) + .when(sut -> "result") + .then("Expectations", () -> {}) + .and("Expectations", () -> { + throw new UnexpectedException(); + })); + + // THEN + LOGGER.debug("Stack trace", thrown); + assertThat(thrown) + .isInstanceOf(VerificationError.class) + .hasMessage("Fails to verify expectations!") + .hasCauseInstanceOf(UnexpectedException.class); + } + + @Test + public void should_fail_to_check_a_result_predicate_given_a_non_void_target_method() { + // WHEN + Throwable thrown = catchThrowable(() -> givenSutClass(SystemUnderTest.class) + .when(sut -> "result") + .then((CheckedPredicate) result -> { + throw new UnexpectedException(); + })); + + // THEN + LOGGER.debug("Stack trace", thrown); + assertThat(thrown) + .isInstanceOf(VerificationError.class) + .hasMessage("Fails to verify the result expectations!") + .hasCauseInstanceOf(UnexpectedException.class); + } + + @Test + public void should_fail_to_check_another_result_predicate_given_a_non_void_target_method() { + // WHEN + Throwable thrown = catchThrowable(() -> givenSutClass(SystemUnderTest.class) + .when(sut -> "result") + .then(result -> true) + .and((CheckedPredicate) result -> { + throw new UnexpectedException(); + })); + + // THEN + LOGGER.debug("Stack trace", thrown); + assertThat(thrown) + .isInstanceOf(VerificationError.class) + .hasMessage("Fails to verify the result expectations!") + .hasCauseInstanceOf(UnexpectedException.class); + } + + @Test + public void should_fail_to_check_result_and_sut_predicates_because_of_the_result_given_a_non_void_target_method() { + // WHEN + Throwable thrown = catchThrowable(() -> givenSutClass(SystemUnderTest.class) + .when(sut -> "result") + .then(result -> { + throw new UnexpectedException(); + }, sut -> true)); + + // THEN + LOGGER.debug("Stack trace", thrown); + assertThat(thrown) + .isInstanceOf(VerificationError.class) + .hasMessage("Fails to verify the result expectations!") + .hasCauseInstanceOf(UnexpectedException.class); + } + + @Test + public void should_fail_to_check_result_and_sut_predicates_because_of_the_sut_given_a_non_void_target_method() { + // WHEN + Throwable thrown = catchThrowable(() -> givenSutClass(SystemUnderTest.class) + .when(sut -> "result") + .then(result -> true, sut -> { + throw new UnexpectedException(); + })); + + // THEN + LOGGER.debug("Stack trace", thrown); + assertThat(thrown) + .isInstanceOf(VerificationError.class) + .hasMessage("Fails to verify the expectations of the system under test!") + .hasCauseInstanceOf(UnexpectedException.class); + } + + @Test + public void should_fail_to_check_some_result_predicates_given_a_non_void_target_method() { + // WHEN + Throwable thrown = catchThrowable(() -> givenSutClass(SystemUnderTest.class) + .when(sut -> "result") + .then(asList(result -> true, result -> { + throw new UnexpectedException(); + }, result -> true))); + + // THEN + LOGGER.debug("Stack trace", thrown); + assertThat(thrown) + .isInstanceOf(VerificationError.class) + .hasMessage("Fails to verify the result expectations!") + .hasCauseInstanceOf(UnexpectedException.class); + } + + @Test + public void should_fail_to_verify_no_failure_happened_during_the_execution_stage() { + // WHEN + Throwable thrown = catchThrowable(() -> when((CheckedRunnable) () -> { + throw new UnexpectedException(); + }).thenItSucceeds()); + + // THEN + LOGGER.debug("Stack trace", thrown); + assertThat(thrown) + .isInstanceOf(AssertionError.class) + .hasMessageContaining(UnexpectedException.class.getName()); + } +} diff --git a/test-as-you-think-core/src/test/java/testasyouthink/WhenFailuresTest.java b/test-as-you-think-core/src/test/java/testasyouthink/WhenFailuresTest.java index 059368e..87e68c4 100644 --- a/test-as-you-think-core/src/test/java/testasyouthink/WhenFailuresTest.java +++ b/test-as-you-think-core/src/test/java/testasyouthink/WhenFailuresTest.java @@ -22,7 +22,6 @@ package testasyouthink; -import org.junit.After; import org.junit.Before; import org.junit.Test; import org.slf4j.Logger; @@ -31,46 +30,40 @@ import testasyouthink.fixture.GivenWhenThenDefinition; import testasyouthink.fixture.SystemUnderTest; import testasyouthink.fixture.UnexpectedException; +import testasyouthink.function.CheckedRunnable; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.catchThrowable; -import static org.easymock.EasyMock.expect; -import static org.easymock.EasyMock.expectLastCall; -import static org.easymock.EasyMock.replay; -import static org.easymock.EasyMock.strictMock; -import static org.easymock.EasyMock.verify; +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verifyZeroInteractions; +import static org.mockito.Mockito.when; import static testasyouthink.TestAsYouThink.givenSut; +import static testasyouthink.TestAsYouThink.when; import static testasyouthink.fixture.Specifications.ExpectedMessage.EXPECTED_EXECUTION_FAILURE_MESSAGE; public class WhenFailuresTest { private static final Logger LOGGER = LoggerFactory.getLogger(WhenFailuresTest.class); private SystemUnderTest systemUnderTestMock; - private GivenWhenThenDefinition givenWhenThenDefinitionMock; + private GivenWhenThenDefinition givenWhenThenDefinition; @Before public void prepareFixtures() { // GIVEN - systemUnderTestMock = strictMock(SystemUnderTest.class); - } - - @After - public void verifyMocks() { - // THEN - verify(systemUnderTestMock); + systemUnderTestMock = mock(SystemUnderTest.class); + givenWhenThenDefinition = mock(GivenWhenThenDefinition.class); } @Test public void should_fail_to_execute_given_a_non_void_method() throws Throwable { // GIVEN - expect(systemUnderTestMock.nonVoidMethodWithThrowsClause()).andThrow(new UnexpectedException()); - givenWhenThenDefinitionMock = strictMock(GivenWhenThenDefinition.class); - replay(systemUnderTestMock, givenWhenThenDefinitionMock); + when(systemUnderTestMock.nonVoidMethodWithThrowsClause()).thenThrow(UnexpectedException.class); // WHEN Throwable thrown = catchThrowable(() -> givenSut(systemUnderTestMock) .when(SystemUnderTest::nonVoidMethodWithThrowsClause) - .then(() -> givenWhenThenDefinitionMock.thenTheActualResultIsInKeepingWithTheExpectedResult())); + .then(() -> givenWhenThenDefinition.thenTheActualResultIsInKeepingWithTheExpectedResult())); // THEN LOGGER.debug("Stack trace", thrown); @@ -78,21 +71,52 @@ public void should_fail_to_execute_given_a_non_void_method() throws Throwable { .isInstanceOf(ExecutionError.class) .hasMessage(EXPECTED_EXECUTION_FAILURE_MESSAGE) .hasCauseInstanceOf(UnexpectedException.class); - verify(givenWhenThenDefinitionMock); + verifyZeroInteractions(givenWhenThenDefinition); } @Test public void should_fail_to_execute_given_a_void_method() throws Throwable { // GIVEN - systemUnderTestMock.voidMethodWithThrowsClause(); - expectLastCall().andThrow(new UnexpectedException()); - givenWhenThenDefinitionMock = strictMock(GivenWhenThenDefinition.class); - replay(systemUnderTestMock, givenWhenThenDefinitionMock); + doThrow(UnexpectedException.class) + .when(systemUnderTestMock) + .voidMethodWithThrowsClause(); // WHEN Throwable thrown = catchThrowable(() -> givenSut(systemUnderTestMock) .when(SystemUnderTest::voidMethodWithThrowsClause) - .then(() -> givenWhenThenDefinitionMock.thenTheActualResultIsInKeepingWithTheExpectedResult())); + .then(() -> givenWhenThenDefinition.thenTheActualResultIsInKeepingWithTheExpectedResult())); + + // THEN + LOGGER.debug("Stack trace", thrown); + assertThat(thrown) + .isInstanceOf(ExecutionError.class) + .hasMessage(EXPECTED_EXECUTION_FAILURE_MESSAGE) + .hasCauseInstanceOf(UnexpectedException.class); + verifyZeroInteractions(givenWhenThenDefinition); + } + + @Test + public void should_fail_to_execute_directly_a_non_void_method() { + // WHEN + Throwable thrown = catchThrowable(() -> when(() -> { + throw new UnexpectedException(); + }).then(() -> givenWhenThenDefinition.thenTheActualResultIsInKeepingWithTheExpectedResult())); + + // THEN + LOGGER.debug("Stack trace", thrown); + assertThat(thrown) + .isInstanceOf(ExecutionError.class) + .hasMessage(EXPECTED_EXECUTION_FAILURE_MESSAGE) + .hasCauseInstanceOf(UnexpectedException.class); + verifyZeroInteractions(givenWhenThenDefinition); + } + + @Test + public void should_fail_to_execute_directly_a_void_method() { + // WHEN + Throwable thrown = catchThrowable(() -> when((CheckedRunnable) () -> { + throw new UnexpectedException(); + }).then(() -> givenWhenThenDefinition.thenTheActualResultIsInKeepingWithTheExpectedResult())); // THEN LOGGER.debug("Stack trace", thrown); @@ -100,6 +124,6 @@ public void should_fail_to_execute_given_a_void_method() throws Throwable { .isInstanceOf(ExecutionError.class) .hasMessage(EXPECTED_EXECUTION_FAILURE_MESSAGE) .hasCauseInstanceOf(UnexpectedException.class); - verify(givenWhenThenDefinitionMock); + verifyZeroInteractions(givenWhenThenDefinition); } } diff --git a/test-as-you-think-core/src/test/java/testasyouthink/WhenStepAsExpressionLambdaTest.java b/test-as-you-think-core/src/test/java/testasyouthink/WhenStepAsExpressionLambdaTest.java index edb9f25..ba1fa81 100644 --- a/test-as-you-think-core/src/test/java/testasyouthink/WhenStepAsExpressionLambdaTest.java +++ b/test-as-you-think-core/src/test/java/testasyouthink/WhenStepAsExpressionLambdaTest.java @@ -28,8 +28,7 @@ import org.mockito.Mockito; import testasyouthink.fixture.GivenWhenThenDefinition; import testasyouthink.fixture.SystemUnderTest; - -import java.util.function.Consumer; +import testasyouthink.function.CheckedConsumer; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; @@ -57,7 +56,7 @@ public void should_accept_a_function_as_a_lambda_without_ambiguity_by_using_an_i // WHEN givenSutClass(SystemUnderTest.class) .when(withReturn(sut -> sut.nonVoidMethod())) - .then((Consumer) result -> givenWhenThenDefinitionMock + .then((CheckedConsumer) result -> givenWhenThenDefinitionMock .thenTheActualResultIsInKeepingWithTheExpectedResult()); } @@ -66,7 +65,7 @@ public void should_accept_a_function_as_a_lambda_without_ambiguity_by_using_an_a // WHEN givenSutClass(SystemUnderTest.class) .whenSutReturns(sut -> sut.nonVoidMethod()) - .then((Consumer) result -> givenWhenThenDefinitionMock + .then((CheckedConsumer) result -> givenWhenThenDefinitionMock .thenTheActualResultIsInKeepingWithTheExpectedResult()); } @@ -76,7 +75,7 @@ public void should_accept_a_bifunction_as_a_lambda_without_ambiguity_by_using_an givenSutClass(SystemUnderTest.class) .givenArgument("one argument", "argument") .whenSutReturns((sut, argument) -> sut.nonVoidMethodWithParameter(argument)) - .then((Consumer) result -> givenWhenThenDefinitionMock + .then((CheckedConsumer) result -> givenWhenThenDefinitionMock .thenTheActualResultIsInKeepingWithTheExpectedResult()); } @@ -87,7 +86,7 @@ public void should_accept_a_trifunction_as_a_lambda_without_ambiguity_by_using_a .givenArgument("first argument", "argument") .andArgument("second argument", 20170622) .whenSutReturns((sut, argument1, argument2) -> sut.nonVoidMethodWithTwoParameters(argument1, argument2)) - .then((Consumer) result -> givenWhenThenDefinitionMock + .then((CheckedConsumer) result -> givenWhenThenDefinitionMock .thenTheActualResultIsInKeepingWithTheExpectedResult()); } @@ -101,7 +100,7 @@ public void should_accept_a_quadrifunction_as_a_lambda_without_ambiguity_by_usin .whenSutReturns( (sut, argument1, argument2, argument3) -> sut.nonVoidMethodWithThreeParameters(argument1, argument2, argument3)) - .then((Consumer) result -> givenWhenThenDefinitionMock + .then((CheckedConsumer) result -> givenWhenThenDefinitionMock .thenTheActualResultIsInKeepingWithTheExpectedResult()); } diff --git a/test-as-you-think-core/src/test/java/testasyouthink/function/MemoizedTest.java b/test-as-you-think-core/src/test/java/testasyouthink/function/MemoizedTest.java new file mode 100644 index 0000000..a4b178d --- /dev/null +++ b/test-as-you-think-core/src/test/java/testasyouthink/function/MemoizedTest.java @@ -0,0 +1,59 @@ +/*- + * #%L + * Test As You Think + * %% + * Copyright (C) 2017 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 + * . + * #L% + */ + +package testasyouthink.function; + +import org.junit.Test; +import org.mockito.Mockito; + +import java.util.function.Supplier; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; + +public class MemoizedTest { + + @Test + public void should_memoize_a_supplied_value() { + // GIVEN + Counter counter = Mockito.mock(Counter.class); + Supplier memoized = Memoized.of(() -> { + counter.count(); + return Math.random(); + }); + Double suppliedValue = memoized.get(); + + // WHEN + Double memoizedResult = memoized.get(); + + // THEN + assertThat(memoizedResult).isEqualTo(suppliedValue); + verify(counter).count(); + verifyNoMoreInteractions(counter); + } + + static class Counter { + + void count() {} + } +}