This commit factors ServerWebExchange mutator support out of
WebTestClient in favor of an independent public class called
MockServerExchangeMutator which implements WebFilter and can be
applied to the WebTestClient as any other WebFilter.
The MockServerExchangeMutator also exposes a method to apply
a client-side filter for "per request" mutators. See the Javadoc
of the MockServerExchangeMutator.
Issue: SPR-15570
This commit introduces a new method in HttpRequest:
`String getMethodValue`, which returns the HTTP method as a String.
Furthermore, HttpRequest.getMethod() has been given a default
implementation using this String value in combination with
`HttpMethod.resolve`.
Issue: SPR-15545
This commit removes the RouterFunctions.toHandlerMapping method, in
favor of native support for RouterFunctions in @EnableWebFlux
configuration classes.
In order to accomplish this, the HandlerStrategies components has been
repurposed to only be used for the "bare-bones" HttpHandler, while the
(newly introduced) RouterFunctionMapping uses the strategies as exposed
through WebFluxConfigurationSupport.
Furthermore, this commit also introduces support for testing
RouterFunctions without resorting to an application context.
Issue: SPR-15536
With this commit, ServerCodecConfigurer is now exposed as a bean in
order to be provided to DefaultServerWebExchange via
WebHttpHandlerBuilder and HttpWebHandlerAdapter. This allows
DefaultServerWebExchange to get configured codecs for reading form or
multipart requests.
Issue: SPR-14546
According to RFC-6265 that there should be a space between the ; and
the attribute name, i.e. the header should be something like
name=value; Domain=localhost; HttpOnly rather than
name=value;Domain=localhost;HttpOnly
Issue: SPR-15225
This commit renames the `body(Object)` on ServerResponse to
`syncBody(Object)`. The reason for this is that the original method
name clashed with the `body(Publisher)` method in the Kotlin extension.
The new name nicely reflects the synchronous nature of the method,
making it less appealing than the `Publisher`-based `body` method.
Issue: SPR-15467
This commit makes changes to WebClient and WebTestClient in oder to
limit setting the body according to HTTP method and also to facilitate
providing the request body as Object.
Specifically, this commit:
- Moves methods that operate on the request body to a RequestBodySpec
in both WebClient and WebTestClient, and rename them to `body`.
These methods now just *set* the body, without performing
an exchange (which now requires an explicit exchange call).
- Parameterizes UriSpec in both WebClient and WebTestClient, so that
it returns either a RequestHeadersSpec or a RequestBodySpec.
Issue: SPR-15394
This commit deprecates `AsyncRestTemplate` and related types
(`AsyncClientHttpRequestFactory` etc.) in favor of the Spring 5.0
`WebClient`.
Issue: SPR-15294
This commit folds ServerHttpMessage[Reader|Writer] into its parent
HttpMessage[Reader|Writer] with the server methods pre-implemented
by default to be simple pass-through delegates.
This commit changes the `MediaTypeFactory` to return
`Optional<MediaType>` (instead of a plain `MediaType`) for the
`getMediaType` methods.
Issue: SPR-14908
This commit changes the `MockServletContext.getMimeType` method to use
`MediaTypeFactory` instead of JAF. It also adds a `addMimeType(String,
MediaType)` method to customize the mime types returned from said
method.
Issue: SPR-14908
ExchangeMutatorWebFilter now supports multiple mutator registrations
for the same request header id by creating a single composed function.
Issue: SPR-15250
This commit adds a common base class for server-less setup with the
option to configure a transformation function on the
ServerWebExchange for every request.
The transformation is applied through a WebFilter. As a result the
RouterFunction setup is now invoked behind a DispatcherHandler with
a HandlerMapping + HandlerAdapter.
Issue: SPR-15250
Currently the BOM versions are:
* reactor-core 3.0.6.BUILD-SNAPSHOT
* reactor-netty 0.6.2.BUILD-SNAPSHOT
This commit fixes as well a few deprecations in reactor-core.
The WebTestClient API no longer provides access to a base
ExchangeResult without a decoded response body.
Instead the response has to be decoded first and tests can then
access the EntityExchangeResult and FluxExchangeResult sub-types.
The WiretapConnector now decorated the ClientHttpRequest & Response
in order to intercept and save the actual content written and read.
The saved content is now incorporated in the diagnostic output but may
be used for other purposes as well (e.g. REST Docs).
Diagnostic information about an exchange has also been refactored
similar to command line output from curl.
Clearly separate how the result of an exchange is represented before
the response body has been read (e.g. assertions on status and headers
only) vs later after the body is extracted to a representation
(assertions on the extracted body) or is decoded to Flux<T> (e.g. for
use with a StepVerifier).
WebTestClient now defines all the steps from setup to performing
an exchange and applying expectations.
The order of expectations now ensures the response status and headers
are verified first since that's available before the body is consumed
and also because it determines how the body is to be decoded, i.e.
error vs success scenarios.
There is now a built-in option for verifying the response as a Map
along with Map-specific assertions.
There are similar options for verifying the response as a List as well
as whether to "collect" the list or "take" the first N elements from
the response stream.
Rather than returning ExchangeActions that contains ExchangeInfo and
applies a chain of assertions, the exchange operation in WebTestClient
now has an extra step to decode the response.
The outcome of that is ExchangeResult<T>, parameterized with the
decoded body type, and containing the request and response details,
also providing access to built-inassertions via an assertThat()
instance method.
This approach lends itself better to decoding and asserting response
body types with generecis. It is also more friendly to using any
assertion library such as AssertJ since you get the result first
and then deal with assertions.
This commit changes the `assertXmlEqual` implementation to compare
expected and actual XML documents without considering the order of XML
nodes.
Issue: SPR-15156
Put assertBodyXyz options behind a common assertBody() entry point
currently including "isEmpty" and "asMap" but in the future others
related to JSON content or XPath for example.
Now that ExchangeActions provides method to access the ExchangeInfo
it has been removed from constructors of assertion classes that
already have ExchangeActions.
This commit removes the parameterisation from ClientRequest, similarly
to ServerResponse. Dropping the parameterisation facilitates a
ClientRequest.from method that also copies the body of the target
request.
SPR-15234 Work in Progress
Before this change the write Publisher was saved and Mono.empty()
returned from the write metohd which did not properly implement
the write contract since no writing ("consuming") was done.
This can be a problem in some cases. For example the request may appear
to succeed even if the publisher produces an error later when
subscribed to later after request handling completes.
This commit introduces a writeHandler function in the mock request and
response. By default it "writes" by consuming the content immediately,
which allows it to return a Mono<Void> that properly reflects when
writing is done, and it also caches the data so it may be replayed
later for test assertions.
For streaming scenario a custom writeHandler may be registered which
allows the custom handling to determine how long to stream before
cancelling so request handling may complete.
Issue: SPR-14590
Prior to this commit, SpringJUnit4ConcurrencyTests was broken due to
recent additions of test methods in SampleTests.
This commit fixes the broken test by removing hard coded constants and
replacing them with dynamic lookups for JUnit 4 @Test methods.
This commit ensures that verifying a request, which includes finding
and updating expectations, is done synchronously to avoid concurrent
modification exceptions.
Technically SimpleRequestExpectationManager is not even expected to see
concurrent requests by definition but with
UnorderedRequestExpectationManager it can happen.
Issue: SPR-15029
MockServerHttpRequest and MockServerHttpResponse now extend the same
abstract base classes that server-specific implementations do and
therefore approximate their behavior more closely.
As an immediate consequence MockServerHttpRequest is read-only after
it is created. Instead it now exposes static builder methods similar
to those found in RequestEntity. This enforces more strictness as well
as recycling of requests in tests and provides nicer builder methods.
To simplify tests DefaultServerWebExchange now offers a constructor
with just a request and response, and automatically creating a
DefaultWebSessionManager.
The spring-test module now also contains client-side reactive mock
request and response implementations. The mock client request extends
the same AbstractClientHttpRequest as client-specific implementations
do. There is no abstract base class for client responses.
Issue: SPR-14590
After the upgrade to JUnit Jupiter 5.0 M3, JUnit Jupiter tests in the
Spring build were no longer executed due to the introduction of a
default test class name pattern.
This commit addresses this issue by making use of the
@IncludeClassNamePatterns to specify that *TestCase test classes should
be executed within the org.springframework.test.context.junit.jupiter
package.
This commit polishes previous one by also accepting
generic types explicitly declared with a class that
extends DataBuffer allowing to write Flux<DefaultDataBuffer>
for example.
Issue: SPR-14952
This modifies the signature of
ReactiveHttpOutputMessage#writeAndFlush(...) in order to
be able to use Flux<Flux<DataBuffer>> objects as arguments of
this method.
Issue: SPR-14952
This commit introduces the `DispatcherServletCustomizer` callback
interface that can be used to customize the `DispatcherServlet` that a
`MockMvc` is using.
Previously, only the `dispatchOptions` flag can be customized. This
commit allows to customize any property of `DispatcherServlet` before it
is initialized.
Issue: SPR-14277
Prior to this commit, when using @EnabledIf or @DisabledIf in Spring's
JUnit Jupiter support, the test's ApplicationContext was always eagerly
loaded, even if the ApplicationContext would never be used (i.e., the
test was disabled). This behavior can lead to undesirable side effects
-- for example, attempting to load an application context that requires
services only available on the CI server when the test is not actually
running on the CI server.
This commit addresses this issue by introducing new boolean
`loadContext` flags in @EnabledIf and @DisabledIf. By default these
flags are set to false which means that the user's test application
context will not be loaded to evaluate the expression. On the contrary,
a dummy application context will be loaded instead, and expressions
will be evaluated against that dummy context. Consequently, if the user
wishes to interact with properties from the Spring Environment or with
beans from the test application context, the `loadContext` must be
explicitly set to true.
In addition, expressions which evaluate to a String must now evaluate
to exactly "true" or "false" (ignoring case and surrounding whitespace).
Issue: SPR-14649
String with version 5 the name of Java Platform, Enterprise Edition
changed from J2EE to Java EE. However a lot of the documentation still
uses the term J2EE.
This commit includes the following changes:
* replace J2EE with Java EE where appropriate
This is not a blind search and replace. The following occurrences
remain unchanged:
* references to old J2EE releases, most notably 1.3 and 1.4.
* references to "Expert One-On-One J2EE Design and Development"
* references to "Core J2EE patterns"
* XML namespaces
* package names
Issue: SPR-14811
See gh-1206
Prior to this commit, the redirectedUrl() and forwardedUrl() methods in
MockMvcResultMatchers supported fully constructed URLs and URLs
containing Ant-style path patterns. However, URI templates were not
supported for these result matchers even though the request path can be
built using URL templates -- for example, via the get() and post()
methods in MockMvcRequestBuilders.
This commit addresses this shortcoming by allowing users to supply a
URL template instead of a fully constructed URL to redirectedUrl() and
forwardedUrl(). To populate the URL template, template variables may be
supplied to redirectedUrl() and forwardedUrl() as var-args.
Issue: SPR-14790
Commit e65a1a4372 introduced support in PrintingResultHandler for only
printing the request or response body in the Spring MVC Test framework
if the content type is known to be text-based (e.g., plain text, HTML,
XHTML, XML, JSON, etc.). For unknown content types the body is assumed
to be text-based and is therefore always printed. The latter behavior,
however, is undesirable since the content may in fact not be text-based.
This commit addresses this issue by making the printing of the request
or response body an opt-in feature. Specifically, if a character
encoding has been set, the request or response body will be printed by
the PrintingResultHandler. Note, however, that the character encoding
is set to ISO-8859-1 in MockHttpServletResponse by default.
In addition, MockHttpServletRequest's getContentAsString() method now
throws an IllegalStateException if the character encoding has not been
set.
Issue: SPR-14776
Prior to this commit, PrintingResultHandler always printed the request
or response body regardless of its content type. For binary content,
however, the output was unreadable and therefore useless.
This commit addresses this issue by only printing the request or
response body if it is "printable" (i.e., if its content type is known
to be text-based such as plain text, HTML, XHTML, XML, JSON, etc.). If
the content type is unknown (e.g., unspecified for the HTTP request in
the test), it is assumed that the body is printable.
Issue: SPR-14776
Prior to this commit, the PrintingResultHandler used by the various
print() and log() methods in Spring MVC Test printed the response body
but not the request body.
Since request bodies are sometimes generated programmatically, however,
it can be beneficial to have the dynamically generated request body
logged as well.
This commit therefore prints the request body in PrintingResultHandler
by delegating to the recently introduced getContentAsString() method in
MockHttpServletRequest.
Issue: SPR-14717
In order to improve debugging and logging within test suites, this
commit introduces getContentAsByteArray() and getContentAsString()
methods in MockHttpServletRequest, analogous to the existing methods in
MockHttpServletResponse.
Issue: SPR-14717
Whereas the existing TestContextConcurrencyTests verify support for
concurrency in the TestContextManager and TestContext, this commit
introduces SpringJUnit4ConcurrencyTests that verify support for
concurrent test execution in Spring's JUnit 4 support, namely in the
SpringRunner, SpringClassRule, and SpringMethodRule.
The tests executed by this new test class come from a hand-picked
collection of test classes within the test suite that is intended to
cover most categories of tests that are currently supported by the
TestContext Framework on JUnit 4.
Note, however, that the chosen test classes intentionally do not
include any classes that fall under the following categories.
- tests that make use of Spring's @DirtiesContext support
- tests that make use of JUnit 4's @FixMethodOrder support
- tests that commit changes to the state of a shared in-memory database
Issue: SPR-5863
This commit improves the exception message thrown when a test's
ApplicationContext is no longer active by explaining that the cause
may be due to parallel test execution.
Issue: SPR-5863
Prior to this commit, executing tests concurrently in the TestContext
Framework (TCF) was unsupported and typically lead to unpredictable
results.
This commit addresses this core issue by supporting concurrent
execution in the TestContextManager and the DefaultTestContext.
Specifically, the TestContextManager now uses ThreadLocal storage for
the current TestContext, thereby ensuring that any registered
TestExecutionListeners and the TestContextManager itself operate on a
TestContext specific to the current thread.
In order to avoid repeatedly incurring the costs of the overhead of the
TCF bootstrapping process, the original TestContext built by the
TestContextBootstrapper is used as a template which is then passed to
the copy constructor of the concrete implementation of the TestContext
to create the context for the current thread. DefaultTestContext now
implements such a copy constructor, and all concrete implementations of
TestContext are encouraged to do the same.
If the TestContext built by the TestContextBootstrapper does not
provide a copy constructor, thread-safety and support for concurrency
are left completely to the implementation of the concrete TestContext.
Note, however, that this commit does not address any thread-safety or
concurrency issues in the ContextLoader SPI or its implementations.
Issue: SPR-5863
This commit inlines the basic implementation of AttributeAccessorSupport
and converts the LinkedHashMap to a ConcurrentHashMap.
In addition, attributes are now included in toString().
Issue: SPR-5863
This commit introduces integration tests that verify the expected
behavior for @Nested tests in conjunction with the SpringExtension for
JUnit Jupiter, including automatic application of
TestExecutionListeners to the enclosing test instance of a @Nested
test instance.
Issue: SPR-14150
Due to restrictions imposed by JUnit 4, the SpringClassRule must be
declared as a public static field, which makes it impossible to be
declared directly within a nested (i.e., inner) test class.
This commit demonstrates a work-around that makes it possible to use
the SpringClassRule and SpringMethodRule in a nested (i.e., inner) test
class when using a custom JUnit 4 runner such as the
HierarchicalContextRunner from Stefan Bechtold.
The trick is to have inner test classes extend a class that properly
declares the SpringClassRule and SpringMethodRule. The
SpringRuleConfigurer in this commit serves as an example.
Note, however, that each such nested test class must declare its own
@ContextConfiguration. Furthermore, TestExecutionListeners in the
Spring TestContext Framework are not applied to the enclosing instance
of such an inner test class, meaning that @Autowired fields in the
enclosing instance will not be injected, etc.
Issue: SPR-14150
This commit picks up where SPR-14614 left off by introducing a new
@EnabledIf annotation to serve as a logical companion to @DisabledIf.
In addition, this commit extracts common logic from DisabledIfCondition
into a new AbstractExpressionEvaluatingCondition base class which the
new EnabledIfCondition also extends.
An @EnabledOnMac annotation is also included in the Javadoc as well as
in the test suite to demonstrate support for custom composed annotations.
Issue: SPR-14644
Prior to this commit, the DisabledIfCondition did not trim whitespace
from expressions configured via @DisabledIf. Consequently, results such
as " true " would evaluate to "false".
This commit fixes this problem by trimming all expressions configured
via @DisabledIf.
Issue: SPR-14614
This commit introduces tests for DisabledIfCondition that verify actual
condition evaluation results and exception handling; whereas, the
existing tests in DisabledIfTestCase only test the "happy paths" and
standard cases.
Issue: SPR-14614
- Extracted stand-alone DisabledIfCondition from the SpringExtension
so that the condition is only evaluated when necessary.
- Simplified implementation of DisabledIfCondition.
- Overhauled and extended logging in DisabledIfCondition.
- DisabledIfCondition now throws an IllegalStateException if @DisabledIf
is not present on the test element or if the expression does not
evaluate to a String or Boolean.
- Each generated ConditionEvaluationResult now includes the actual
expression in the default reason.
- @DisabledIf is now auto-configured to be evaluated by the
DisabledIfCondition since it is now meta-annotated with
@ExtendWith(DisabledIfCondition.class)
- Overhauled documentation for @DisabledIf and provided standard
examples as well as an @DisabledOnMac annotation to demonstrate
support for custom composed annotations.
Issue: SPR-14614
This commit introduces @DisabledIf annotation that takes SpEL as a
condition. The condition is evaluated at run time whether to disable
JUnit 5 (Jupiter) test method/class.
Issue: SPR-14614
This change adds support for a target type in JsonPath assertions in
Spring MVC Test.
The existing assertValue(String expression, Object expectedValue)
transparently falls back on using an alternative JsonPath API that
allows specifying the target type to coerce to.
There is also a new overloaded method
assertValue(String expression, Matcher<T> matcher, Class<T> targetType)
for use with Hamcrest matchers where the target type can be specified.
Issue: SPR-14498
Previously invoking HtmlUnitRequestBuilder merge caused the pathInfo of
the parent to be corrupted. This could additional invocations with the
same parent.
This fix ensures that the parent is no longer directly used. Instead,
we create a copy of the parent by merging the parent that was passed in
with the copy.
Fixes SPR-14584
xmlunit 2.1.0 is the latest release for xmlunit.
Most of the xmlunit functionality used within spring-framework
was done through the xmlunit 1.x helper class
`org.custommonkey.xmlunit.XMLAssert`.
As of xmlunit 2.0.0 most of the XML comparison methods are done
through hamcrest matchers exposed by the xmlunit-matchers
library. In some cases during the migration, the matchers
had to be customized with custom `NodeMatcher` or
`DifferenceEvaluator` instances in order to keep the assertions
correct (they were performed with xmlunit 1.x previously).
Issue: SPR-14043
Prior to this commit, a dynamic test in
FailingBeforeAndAfterMethodsSpringExtensionTestCase was failing but for
the wrong reason. Namely, the @Configuration class was private which
resulted in an IllegalStateException being thrown, when in fact
an AssertionFailedError was expected.
This commit addresses this by introducing an explicit check for an
AssertionFailedError.
Issue: SPR-4365
Prior to this commit, if multiple TestExecutionListener 'after' methods
threw an exception, only the first such exception was rethrown.
Subsequent exceptions were logged, but there was no way to access or
process them other than via the log file.
This commit addresses this shortcoming by making use of the support for
suppressed exceptions introduced in Java 7. Specifically, if multiple
TestExecutionListener 'after' methods throw an exception, the first
exception will be rethrown with subsequent exceptions suppressed in the
first one.
Issue: SPR-14459
This commit makes use of the new Supplier<String> variants of utility
methods in org.springframework.util.Assert within the spring-test
module.
Issue: SPR-14450
SPR-14055 introduced first-class support for the Java 8 Parameter API.
This commit therefore replaces the MethodParameterFactory with use of
the new SynthesizingMethodParameter.forParameter(Parameter) factory
method.
Issue: SPR-13575
This commit adds a test runtime dependency on log4j 2 for every project
and migrates all log4j.properties files to log4j2-test.xml files.
Issue: SPR-14431
This commit also removes the corresponding deprecated Servlet MVC variant and updates DispatcherServlet.properties to point to RequestMappingHandlerMapping/Adapter by default.
Issue: SPR-14129
This commit introduces initial support for JUnit Jupiter (i.e., the new
programming and extension models in JUnit 5) in the Spring TestContext
Framework.
Specifically, this commit introduces the following.
- SpringExtension: an implementation of multiple extension APIs from
JUnit Jupiter that provides full support for the existing feature set
of the Spring TestContext Framework. This support is enabled via
@ExtendWith(SpringExtension.class).
- @SpringJUnitConfig: a composed annotation that combines
@ExtendWith(SpringExtension.class) from JUnit Jupiter with
@ContextConfiguration from the Spring TestContext Framework.
- @SpringJUnitWebConfig: a composed annotation that combines
@ExtendWith(SpringExtension.class) from JUnit Jupiter with
@ContextConfiguration and @WebAppConfiguration from the Spring
TestContext Framework.
Issue: SPR-13575
Prior to this commit, any attempt to include a bean of type
ServletServerContainerFactoryBean in the WebApplicationContext for an
integration test class annotated with @WebAppConfiguration in
conjunction the Spring TestContext Framework (TCF) would have resulted
in an IllegalStateException stating that "A ServletContext is required
to access the javax.websocket.server.ServerContainer instance."
In such scenarios, the MockServletContext was in fact present in the
WebApplicationContext; however there was no WebSocket ServerContainer
stored in the ServletContext.
This commit addresses this issue by introducing the following.
- MockServerContainer: a private mock implementation of the
javax.websocket.server.ServerContainer interface.
- MockServerContainerContextCustomizer: a ContextCustomizer that
instantiates a new MockServerContainer and stores it in the
ServletContext under the attribute named
"javax.websocket.server.ServerContainer".
- MockServerContainerContextCustomizerFactory: a
ContextCustomizerFactory which creates a
MockServerContainerContextCustomizer if WebSocket support is present
in the classpath and the test class is annotated with
@WebAppConfiguration. This factory is registered by default via the
spring.factories mechanism.
Issue: SPR-14367
ReflectionTestUtils invokes toString() on target objects in order to
build exception and logging messages, and prior to this commit problems
could occur if the invocation of toString() threw an exception.
This commit addresses this issue by ensuring that all invocations of
toString() on target objects within ReflectionTestUtils are performed
safely within try-catch blocks.
Issue: SPR-14363
Previously MockMvcWebConnection did not update the cookie manager with the
cookies from MockHttpServletResponse. This meant that newly added cookies
are not saved to the cookie manager and thus are not presented in the next
request.
This commit ensures that MockMvcWebConnection stores the response cookies
in the cookie manager.
Issue: SPR-14265
Prior to Java 8 it never really made much sense to author integration
tests using interfaces. Consequently, the Spring TestContext Framework
has never supported finding test-related annotations on interfaces in
its search algorithms.
However, Java 8's support for interface default methods introduces new
testing use cases for which it makes sense to declare test
configuration (e.g., @ContextConfiguration, etc.) on an interface
containing default methods instead of on an abstract base class.
This commit ensures that all non-repeatable, class-level test
annotations in the Spring TestContext Framework can now be declared on
test interfaces. The only test annotations that cannot be declared on
interfaces are therefore @Sql and @SqlGroup.
Issue: SPR-14184