Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -10,27 +10,59 @@ and for those thrown during one of test lifecycle methods (`@BeforeAll`, `@Befor
The following example shows an extension which will swallow all instances of `IOException`
but rethrow any other type of exception.

[source,java,indent=0]
.An exception handling extension that filters IOExceptions in test execution
[tabs]
====
Java::
+
--
[source,java,indent=0]
----
include::example$java/example/exception/IgnoreIOExceptionExtension.java[tags=user_guide]
----
--

Kotlin::
+
--
[source,kotlin,indent=0]
----
include::example$kotlin/example/kotlin/exception/IgnoreIOExceptionExtension.kt[tags=user_guide]
----
--
====

Another example shows how to record the state of an application under test exactly at
the point of unexpected exception being thrown during setup and cleanup. Note that unlike
the point where an unexpected exception is thrown during setup and cleanup. Note that unlike
relying on lifecycle callbacks, which may or may not be executed depending on the test
status, this solution guarantees execution immediately after failing `@BeforeAll`,
`@BeforeEach`, `@AfterEach` or `@AfterAll`.

[source,java,indent=0]
.An exception handling extension that records application state on error
[tabs]
====
Java::
+
--
[source,java,indent=0]
----
include::example$java/example/exception/RecordStateOnErrorExtension.java[tags=user_guide]
----
--

Kotlin::
+
--
[source,kotlin,indent=0]
----
include::example$kotlin/example/kotlin/exception/RecordStateOnErrorExtension.kt[tags=user_guide]
----
--
====

Multiple execution exception handlers may be invoked for the same lifecycle method in
order of declaration. If one of the handlers swallows the handled exception, subsequent
ones will not be executed, and no failure will be propagated to JUnit engine, as if the
ones will not be executed, and no failure will be propagated to the JUnit engine, as if the
exception was never thrown. Handlers may also choose to rethrow the exception or throw
a different one, potentially wrapping the original.

Expand All @@ -39,8 +71,24 @@ exceptions thrown during `@BeforeAll` or `@AfterAll` need to be registered on a
while handlers for `BeforeEach` and `AfterEach` may be also registered for individual
test methods.

[source,java,indent=0]
.Registering multiple exception handling extensions
[tabs]
====
Java::
+
--
[source,java,indent=0]
----
include::example$java/example/exception/MultipleHandlersTestCase.java[tags=user_guide]
----
--

Kotlin::
+
--
[source,kotlin,indent=0]
----
include::example$kotlin/example/kotlin/exception/MultipleHandlersTestCase.kt[tags=user_guide]
----
--
====
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,27 @@ test code.
The following example shows an extension that executes all test methods in Swing's Event
Dispatch Thread.

[source,java,indent=0]
.An extension that executes tests in a user-defined thread
[tabs]
====
Java::
+
--
[source,java,indent=0]
----
include::example$java/example/interceptor/SwingEdtInterceptor.java[tags=user_guide]
----
--

Kotlin::
+
--
[source,kotlin,indent=0]
----
include::example$kotlin/example/kotlin/interceptor/SwingEdtInterceptor.kt[tags=user_guide]
----
--
====

[NOTE]
.Accessing the test-scoped `ExtensionContext`
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,27 @@ will only be used for the next invocation of the `{ClassTemplate}`.
The following example shows how to write a class template as well as how to register
and implement a `{ClassTemplateInvocationContextProvider}`.

.A class template with an accompanying extension
[tabs]
====
Java::
+
--
[source,java,indent=0]
.A class template with accompanying extension
----
include::example$java/example/ClassTemplateDemo.java[tags=user_guide]
----
--

Kotlin::
+
--
[source,kotlin,indent=0]
----
include::example$kotlin/example/kotlin/ClassTemplateDemo.kt[tags=user_guide]
----
--
====

In this example, the class template will be invoked twice, meaning all test methods in
the class template will be executed twice. The display names of the invocations will be
Expand All @@ -33,9 +49,9 @@ output when using the `ConsoleLauncher` is as follows.

The `{ClassTemplateInvocationContextProvider}` extension API is primarily intended for
implementing different kinds of tests that rely on repetitive invocation of _all_ test
methods in a test class albeit in different contexts — for example, with different
methods in a test class, albeit in different contexts — for example, with different
parameters, by preparing the test class instance differently, or multiple times without
modifying the context.
Please refer to the implementations of
Please refer to the implementation of
xref:writing-tests/parameterized-classes-and-tests.adoc[Parameterized Classes] which uses this extension
point to provide its functionality.
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,27 @@ for the next invocation of the `{TestTemplate}` method.
The following example shows how to write a test template as well as how to register and
implement a `{TestTemplateInvocationContextProvider}`.

.A test template with an accompanying extension
[tabs]
====
Java::
+
--
[source,java,indent=0]
.A test template with accompanying extension
----
include::example$java/example/TestTemplateDemo.java[tags=user_guide]
----
--

Kotlin::
+
--
[source,kotlin,indent=0]
----
include::example$kotlin/example/kotlin/TestTemplateDemo.kt[tags=user_guide]
----
--
====

In this example, the test template will be invoked twice. The display names of the
invocations will be `apple` and `banana` as specified by the invocation context. Each
Expand All @@ -28,7 +44,7 @@ parameter. The output when using the `ConsoleLauncher` is as follows.

The `{TestTemplateInvocationContextProvider}` extension API is primarily intended for
implementing different kinds of tests that rely on repetitive invocation of a test-like
method albeit in different contexts — for example, with different parameters, by preparing
method, albeit in different contexts — for example, with different parameters, by preparing
the test class instance differently, or multiple times without modifying the context.
Please refer to the implementations of xref:writing-tests/repeated-tests.adoc[] or
xref:writing-tests/parameterized-classes-and-tests.adoc[Parameterized Tests] which use this extension point
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ NOTE: See also: xref:writing-tests/test-execution-order.adoc[]

The following diagram illustrates the relative order of user-supplied code and extension
code. User-supplied test and lifecycle methods are shown in orange, with callback code
implemented by extensions shown in blue. The grey box denotes the execution of a single
implemented by extensions shown in blue. The gray box denotes the execution of a single
test method and will be repeated for every test method in the test class.

[[diagram]]
Expand Down Expand Up @@ -65,7 +65,7 @@ extension code executed after all tests of the container are executed

In the simplest case only the actual test method will be executed (step 9); all other
steps are optional depending on the presence of user code or extension support for the
corresponding lifecycle callback. For further details on the various lifecycle callbacks
corresponding lifecycle callback. For further details on the various lifecycle callbacks,
please consult the respective Javadoc for each annotation and extension.

All invocations of user code methods in the above table can additionally be intercepted
Expand Down Expand Up @@ -119,32 +119,98 @@ for user-supplied _lifecycle methods_ (see xref:writing-tests/definitions.adoc[]
The following examples demonstrate this behavior. Please note that the examples do not
actually do anything realistic. Instead, they mimic common scenarios for testing
interactions with the database. All methods imported statically from the `Logger` class
log contextual information in order to help us better understand the execution order of
log contextual information to help better understand the execution order of
user-supplied callback methods and callback methods in extensions.
In Kotlin examples, the corresponding methods are top-level functions in the same package
and therefore don't require imports.

[source,java,indent=0]
.Extension1
[tabs]
====
Java::
+
--
[source,java,indent=0]
----
include::example$java/example/callbacks/Extension1.java[tags=user_guide]
----
--

Kotlin::
+
--
[source,kotlin,indent=0]
----
include::example$kotlin/example/kotlin/callbacks/Extension1.kt[tags=user_guide]
----
--
====

[source,java,indent=0]
.Extension2
[tabs]
====
Java::
+
--
[source,java,indent=0]
----
include::example$java/example/callbacks/Extension2.java[tags=user_guide]
----
--

Kotlin::
+
--
[source,kotlin,indent=0]
----
include::example$kotlin/example/kotlin/callbacks/Extension2.kt[tags=user_guide]
----
--
====

[source,java,indent=0]
.AbstractDatabaseTests
[tabs]
====
Java::
+
--
[source,java,indent=0]
----
include::example$java/example/callbacks/AbstractDatabaseTests.java[tags=user_guide]
----
--

Kotlin::
+
--
[source,kotlin,indent=0]
----
include::example$kotlin/example/kotlin/callbacks/AbstractDatabaseTests.kt[tags=user_guide]
----
--
====

[source,java,indent=0]
.DatabaseTestsDemo
[tabs]
====
Java::
+
--
[source,java,indent=0]
----
include::example$java/example/callbacks/DatabaseTestsDemo.java[tags=user_guide]
----
--

Kotlin::
+
--
[source,kotlin,indent=0]
----
include::example$kotlin/example/kotlin/callbacks/DatabaseTestsDemo.kt[tags=user_guide]
----
--
====

When the `DatabaseTestsDemo` test class is executed, the following is logged.

Expand All @@ -160,7 +226,7 @@ When the `DatabaseTestsDemo` test class is executed, the following is logged.
@AfterEach AbstractDatabaseTests.disconnectFromDatabase()
Extension2.afterEach()
Extension1.afterEach()
@BeforeAll DatabaseTestsDemo.afterAll()
@AfterAll DatabaseTestsDemo.afterAll()
@AfterAll AbstractDatabaseTests.destroyDatabase()
----

Expand Down Expand Up @@ -200,11 +266,27 @@ are executed.
* The database connection is closed _before_ deleting the test data, which results in a
failure to connect to the database.

[source,java,indent=0]
.BrokenLifecycleMethodConfigDemo
[tabs]
====
Java::
+
--
[source,java,indent=0]
----
include::example$java/example/callbacks/BrokenLifecycleMethodConfigDemo.java[tags=user_guide]
----
--

Kotlin::
+
--
[source,kotlin,indent=0]
----
include::example$kotlin/example/kotlin/callbacks/BrokenLifecycleMethodConfigDemo.kt[tags=user_guide]
----
--
====

When the `BrokenLifecycleMethodConfigDemo` test class is executed, the following is logged.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

// tag::user_guide[]

import static example.callbacks.Logger.afterAllMethod;
import static example.callbacks.Logger.afterEachMethod;
import static example.callbacks.Logger.beforeAllMethod;
import static example.callbacks.Logger.beforeEachMethod;
Expand Down Expand Up @@ -54,7 +55,7 @@ void deleteTestDataFromDatabase() {

@AfterAll
static void afterAll() {
beforeAllMethod(DatabaseTestsDemo.class.getSimpleName() + ".afterAll()");
afterAllMethod(DatabaseTestsDemo.class.getSimpleName() + ".afterAll()");
}

}
Expand Down
Loading