Commit Graph

1317 Commits

Author SHA1 Message Date
Juergen Hoeller
5f5cd8a7c4 Log resource path resolution failure at debug level (instead of warn)
Closes gh-26828
2021-05-11 15:46:21 +02:00
Sam Brannen
d79e33b5a0 Handle empty file input in HtmlUnitRequestBuilder
This commit revises the fix submitted in 959e6d1745 by ensuring that
empty file input is converted to a MockPart with the supplied name, an
empty filename, "application/octet-stream" as the content type, and
empty content.

This aligns with the behavior of Servlet containers, as tested with the
interaction between Firefox and a standard Servlet running in a Jetty
Servlet container.

Closes gh-26799
2021-05-07 16:00:09 +02:00
Sam Brannen
959e6d1745 Handle empty file input in HtmlUnitRequestBuilder
Prior to this commit, when using HtmlUnit with empty file input,
MockMvc's HtmlUnitRequestBuilder would throw a NullPointerException
when attempting to create a MockPart based on the null File.

This commit ensures that empty file input is converted to a MockPart
with a valid name but with a null filename, a null content type, and
empty content.

Closes gh-26799
2021-05-05 18:11:15 +02:00
Sam Brannen
e4f753e3e3 Honor class-level @DirtiesContext if test class is disabled via SpEL
Prior to this commit, if a test class annotated with @DirtiesContext
and @EnabledIf/@DisabledIf with `loadContext = true` was disabled due
to the evaluated SpEL expression, the ApplicationContext would not be
marked as dirty and closed.

The reason is that @EnabledIf/@DisabledIf are implemented via JUnit
Jupiter's ExecutionCondition extension API which results in the entire
test class (as well as any associated extension callbacks) being
skipped if the condition evaluates to `disabled`. This effectively
prevents any of Spring's TestExecutionListener APIs from being invoked.
Consequently, the DirtiesContextTestExecutionListener does not get a
chance to honor the class-level @DirtiesContext declaration.

This commit fixes this by implementing part of the logic of
DirtiesContextTestExecutionListener in
AbstractExpressionEvaluatingCondition (i.e., the base class for
@EnabledIf/@DisabledIf support). Specifically, if the test class for an
eagerly loaded ApplicationContext is disabled,
AbstractExpressionEvaluatingCondition will now mark the test
ApplicationContext as dirty if the test class is annotated with
@DirtiesContext.

Closes gh-26694
2021-03-18 13:51:32 +01:00
Juergen Hoeller
4f14291e2f Add since tag
See gh-19647
2021-03-15 18:00:54 +01:00
Rossen Stoyanchev
c6b271f1b6 Support global Consumer<ExchangeResult> in WebTestClient
Closes gh-26662
2021-03-15 09:56:17 +00:00
Juergen Hoeller
c1b1940dd2 Polishing 2021-03-12 11:02:35 +01:00
Juergen Hoeller
97b3aa4b13 Polishing 2021-03-12 00:14:04 +01:00
Michal Stehlik
79b5710386 StatusAssertion value methods fail when used with custom status code 2021-03-11 15:57:32 +01:00
Johnny Lim
cf4e77907f Fix MockHttpServletRequest reference in Javadoc
Closes gh-26592
2021-02-23 10:43:38 +01:00
Rossen Stoyanchev
274db2f7a9 Undo HttpServletMapping support in MockHttpServletRequest
Closes gh-26555
2021-02-19 12:07:05 +00:00
Sam Brannen
49ccd7ad9c Polish MockHttpServletResponseTests
See gh-26558
2021-02-17 14:32:39 +01:00
Koos Gadellaa
40661d62c1 Support cookie w/ only Expires attribute in MockHttpServletResponse
Prior to this commit, MockHttpServletResponse only included the Expires
attribute in the generated Cookie header if the Max-Age attribute had
also been set.

This commit supports including the Expires attribute in the generated
Cookie Header even when the Max-Age attribute has not been set.

Closes gh-26558
2021-02-17 14:32:39 +01:00
Sam Brannen
e17ca9a4e9 Implement toString() in MockCookie 2021-02-17 14:32:38 +01:00
Juergen Hoeller
ca8261cbf8 Polishing 2021-02-15 17:18:01 +01:00
Juergen Hoeller
df977a2fd2 Nullability refinements and related polishing 2021-02-14 17:57:32 +01:00
Rossen Stoyanchev
c52526ad42 Fix in MockMultipartHttpServletRequest#getMultipartHeaders
Previously this method returned headers only when a Content-Type part header
was present. Now it is guaranteed to return headers (possibly empty) as long
as there is a MultipartFile or Part with the given name.

Closes gh-26501
2021-02-03 21:55:42 +00:00
Sam Brannen
1a3ff83157 Remove obsolete code in HeaderValueHolder 2021-02-02 11:28:32 +01:00
Sam Brannen
c19b2851f1 Ignore null Locale in MockHttpServletResponse
Prior to this commit, calls to setLocale() MockHttpServletResponse
would result in a NullPointerException if the supplied Locale was null.

Although the Javadoc for setLocale(Locale) and addHeader(String, String)
in javax.servlet.ServletResponse does not specify how a null
Locale should be handled, both Tomcat and Jetty simply ignore a null
value.

This commit therefore updates MockHttpServletResponse to silently
ignore a null Locale passed to setLocale().

Closes gh-26493
2021-02-02 11:18:34 +01:00
Sam Brannen
3b4a3431d4 Ignore null header value in MockHttpServletResponse
Prior to this commit, calls to setHeader() and addHeader() in
MockHttpServletResponse would result in an IllegalArgumentException or
NullPointerException if the supplied header value was null.

Although the Javadoc for setHeader(String, String) and
addHeader(String, String) in javax.servlet.http.HttpServletResponse
does not specify how a null header value should be handled, both Tomcat
and Jetty simply ignore a null value. Furthermore,
org.springframework.http.HttpHeaders.add(String, String) declares the
headerValue parameter as @Nullable.

This commit therefore updates MockHttpServletResponse to silently
ignore null header values passed to setHeader() and addHeader().

Closes gh-26488
2021-02-02 11:18:34 +01:00
Rossen Stoyanchev
f22e2ac578 Add HttpServletMapping support to MockHttpServletRequest
See gh-26428
2021-01-26 17:30:16 +00:00
Sam Brannen
4a7a2258f9 Unwrap proxied DataSources in SqlScriptsTestExecutionListener
Prior to this commit, if the DataSource in the
DataSourceFromTransactionManager was wrapped in a proxy implementing
InfrastructureProxy, SqlScriptsTestExecutionListener would throw an
exception stating that the DataSource in the ApplicationContext and the
DataSource in the DataSourceFromTransactionManager were not the same.

This commit unwraps both data sources and compares the underlying
target instances to check for equality.

In addition, this commit makes the unwrapResourceIfNecessary() method in
TransactionSynchronizationUtils public.

Closes gh-26422
2021-01-22 18:22:00 +01:00
Rossen Stoyanchev
584dabbb39 Add all non-file parts as request parameters
Closes gh-26400
2021-01-19 20:49:59 +00:00
Rossen Stoyanchev
35225e5794 Add verify(Duration) to MockRestServiceServer
Closes gh-22618
2021-01-13 17:50:01 +00:00
Rossen Stoyanchev
a1cf6bbc37 Avoid wrapping of AssertionError in ExchangeResult
Closes gh-26303
2021-01-06 21:56:14 +00:00
Rossen Stoyanchev
fb2e53276c Assert WebFlux present for WebTestClient
Closes gh-26308
2021-01-06 21:56:14 +00:00
Sam Brannen
1565f4b83e Introduce ApplicationEvents to assert events published during tests
This commit introduces a new feature in the Spring TestContext
Framework (TCF) that provides support for recording application events
published in the ApplicationContext so that assertions can be performed
against those events within tests. All events published during the
execution of a single test are made available via the ApplicationEvents
API which allows one to process the events as a java.util.Stream.

The following example demonstrates usage of this new feature.

@SpringJUnitConfig(/* ... */)
@RecordApplicationEvents
class OrderServiceTests {

    @Autowired
    OrderService orderService;

    @Autowired
    ApplicationEvents events;

    @Test
    void submitOrder() {
        // Invoke method in OrderService that publishes an event
        orderService.submitOrder(new Order(/* ... */));
        // Verify that an OrderSubmitted event was published
        int numEvents = events.stream(OrderSubmitted.class).count();
        assertThat(numEvents).isEqualTo(1);
    }
}

To enable the feature, a test class must be annotated or meta-annotated
with @RecordApplicationEvents. Behind the scenes, a new
ApplicationEventsTestExecutionListener manages the registration of
ApplicationEvents for the current thread at various points within the
test execution lifecycle and makes the current instance of
ApplicationEvents available to tests via an @Autowired field in the
test class. The latter is made possible by a custom ObjectFactory that
is registered as a "resolvable dependency". Thanks to the magic of
ObjectFactoryDelegatingInvocationHandler in the spring-beans module,
the ApplicationEvents instance injected into test classes is
effectively a scoped-proxy that always accesses the ApplicationEvents
managed for the current test.

The current ApplicationEvents instance is stored in a ThreadLocal
variable which is made available in the ApplicationEventsHolder.
Although this class is public, it is only intended for use within the
TCF or in the implementation of third-party extensions.

ApplicationEventsApplicationListener is responsible for listening to
all application events and recording them in the current
ApplicationEvents instance. A single
ApplicationEventsApplicationListener is registered with the test's
ApplicationContext by the ApplicationEventsTestExecutionListener.

The SpringExtension has also been updated to support parameters of type
ApplicationEvents via the JUnit Jupiter ParameterResolver extension
API. This allows JUnit Jupiter based tests to receive access to the
current ApplicationEvents via test and lifecycle method parameters as
an alternative to @Autowired fields in the test class.

Closes gh-25616
2020-12-20 23:46:19 +01:00
Juergen Hoeller
fbd2ffdd23 Consistent declarations and assertions in MockMultipartFile
See gh-26261
2020-12-16 22:27:33 +01:00
Sam Brannen
b3a47c76f8 Introduce TestContextAnnotationUtils.hasAnnotation() 2020-12-15 22:48:33 +01:00
Sam Brannen
1292947f78 Introduce computeAttribute() in AttributeAccessor
This commit introduces computeAttribute() as an interface default method
in the AttributeAccessor API. This serves as a convenience analogous to
the computeIfAbsent() method in java.util.Map.

Closes gh-26281
2020-12-15 22:47:02 +01:00
Rossen Stoyanchev
bcfbde9848 Parse parts in MockMultipartHttpServletRequestBuilder
Closes gh-26261
2020-12-14 21:13:29 +00:00
Rossen Stoyanchev
d82cb15439 Ensure both mock files and parts can be provided
Closes gh-26166
2020-12-03 17:53:26 +00:00
Sam Brannen
0819a9fcc9 Discover @DynamicPropertySource methods on enclosing test classes
gh-19930 introduced support for finding class-level test configuration
annotations on enclosing classes when using JUnit Jupiter @Nested test
classes, but support for @DynamicPropertySource methods got overlooked
since they are method-level annotations.

This commit addresses this shortcoming by introducing full support for
@NestedTestConfiguration semantics for @DynamicPropertySource methods
on enclosing classes.

Closes gh-26091
2020-11-15 20:59:15 +01:00
Sam Brannen
3851b291da Use MethodFilter.and() in TransactionalTestExecutionListener 2020-11-11 11:11:34 +01:00
Sam Brannen
fc5e3c335f Introduce and() methods in MethodFilter & FieldFilter for composition
This commit introduces `and()` default methods in the MethodFilter and
FieldFilter functional interfaces in ReflectionUtils in order to simplify
uses cases that need to compose filter logic.

Closes gh-26063
2020-11-10 18:00:24 +01:00
Sam Brannen
b019f30a15 Validate that test & lifecycle methods are not @Autowired
Prior to this commit, a developer may have accidentally annotated a
JUnit Jupiter test method or lifecycle method with @Autowired, and that
would have potentially resulted in an exception that was hard to
understand. This is because the Spring container considers any
@Autowired method to be a "configuration method" when autowiring the
test class instance. Consequently, such an @Autowired method would be
invoked twice: once by Spring while attempting to autowire the test
instance and another time by JUnit Jupiter when invoking the test or
lifecycle method. The autowiring invocation of the method often leads
to an exception, either because Spring cannot satisfy a dependency (such
as JUnit Jupiter's TestInfo) or because the body of the method fails due
to test setup that has not yet been invoked.

This commit introduces validation for @Autowired test and lifecycle
methods in the SpringExtension that will throw an IllegalStateException
if any @Autowired method in a test class is also annotated with any of
the following JUnit Jupiter annotations.

- @Test
- @TestFactory
- @TestTemplate
- @RepeatedTest
- @ParameterizedTest
- @BeforeAll
- @AfterAll
- @BeforeEach
- @AfterEach

Closes gh-25966
2020-11-10 15:28:34 +01:00
Juergen Hoeller
bd2640a9d6 Strict nullability for field assignment 2020-11-09 21:33:32 +01:00
Sam Brannen
b077e4cd85 Use MergedAnnotationCollectors again in TestContextAnnotationUtils
See gh-26031
2020-11-04 14:42:19 +01:00
Sam Brannen
68934f1b79 Use TYPE_HIERARCHY strategy in AnnoDescr.findAllLocalMergedAnnotations()
Prior to this commit, the findAllLocalMergedAnnotations() method in
AnnotationDescriptor altered between the use of TYPE_HIERARCHY and
TYPE_HIERARCHY_AND_ENCLOSING_CLASSES for the SearchStrategy, depending
on @NestedTestConfiguration semantics; however, when searching for
"local" annotations, there is no need to search the enclosing class
hierarchy since AnnotationDescriptor#next() handles that use case.

This commit therefore switches to using only the TYPE_HIERARCHY
strategy.

This commit also discontinues the use of
MergedAnnotationCollectors.toAnnotationSet() in order to avoid the
unnecessary creation of a temporary List when collecting synthesized
annotations in a LinkedHashSet.

Closes gh-25985
2020-11-03 16:17:15 +01:00
Sam Brannen
5628c8cd63 Polish ActiveProfilesUtils 2020-11-03 14:46:17 +01:00
Sam Brannen
acbbf61be8 Preserve registration order in @ActiveProfiles
With this commit, bean definition profiles declared via @ActiveProfiles
are once again stored in registration order, in order to support use
cases in Spring Boot and other frameworks that depend on the
registration order.

This effectively reverts the changes made in conjunction with gh-25973.

Closes gh-26004
2020-11-02 16:39:59 +01:00
Sam Brannen
9c2fd0bd05 Document @DynamicPropertySource use cases that require @DirtiesContext
Closes gh-25850
2020-10-27 14:26:40 +01:00
Sam Brannen
fc9650a9a6 Finalize API for TestContextAnnotationUtils 2020-10-27 00:22:03 +01:00
Juergen Hoeller
0aa3205e38 Fix nullability warnings 2020-10-26 22:19:26 +01:00
Sébastien Deleuze
d04c5f8b2c Support multiple matchers in MockMvc Kotlin DSL
Previous incarnation of MockMvc Kotlin DSL tried to reuse directly
Java APIs like ModelResultMatchers or StatusResultMatchers, but
when using multiple matchers in DSL blocks like model { } or
status { }, only the last statement was taken in account which
was very confusing.

This refactoring provides dedicated Kotlin DSLs for matchers.

The main API breaking changes is that functions like isOk() need to be
invoked with the parenthesis, isOk is not supported anymore (on purpose).

Closes gh-24103
2020-10-26 18:13:55 +01:00
Sam Brannen
ada255d584 Ignore duplicate config metadata for cache key in TestContext framework
Prior to this commit, if a developer accidentally copied and pasted the
same @ContextConfiguration or @TestPropertySource declaration from a
test class to one of its subclasses or nested test classes, the Spring
TestContext Framework (TCF) would merge the inherited configuration
with the local configuration, resulting in different sets of
configuration metadata which in turn resulted in a different
ApplicationContext instance being loaded for the test classes. This
behavior led to unnecessary creation of identical application contexts
in the context cache for the TCF stored under different keys.

This commit ignores duplicate configuration metadata when generating
the ApplicationContext cache key (i.e., MergedContextConfiguration) in
the TCF. This is performed for the following annotations.

- @ContextConfiguration
- @ActiveProfiles (support already existed prior to this commit)
- @TestPropertySource

Specifically, if @ContextConfiguration or @TestPropertySource is
declared on a test class and its subclass or nested test class with the
exact same attributes, only one instance of the annotation will be used
to generate the cache key for the resulting ApplicationContext. The
exception to this rule is an "empty" annotation declaration. An empty
@ContextConfiguration or @TestPropertySource declaration signals that
Spring (or a third-party SmartContextLoader) should detect default
configuration specific to the annotated class. Thus, multiple empty
@ContextConfiguration or @TestPropertySource declarations within a test
class hierarchy are not considered to be duplicate configuration and
are therefore not ignored.

Since @TestPropertySource is a @Repeatable annotation, the same
duplicate configuration detection logic is applied for multiple
@TestPropertySource declarations on a single test class or test
interface.

In addition, this commit reinstates validation of the rules for
repeated @TestPropertySource annotations that was removed when support
for @NestedTestConfiguration was introduced.

Closes gh-25800
2020-10-26 17:17:53 +01:00
Sam Brannen
b1fef925af Cache DefaultActiveProfilesResolver instance since it is stateless 2020-10-26 13:58:45 +01:00
Sam Brannen
9287c15583 Simplify implementation of DefaultActiveProfilesResolver 2020-10-26 13:53:23 +01:00
Sam Brannen
9a4a593c7f Merge branch '5.2.x' 2020-10-26 12:53:53 +01:00
Sam Brannen
c840ba9989 Avoid cache miss for @ActiveProfiles w/ same profiles but different order
Prior to this commit, two @ActiveProfiles declarations with the same
profiles but different order resulted in an identical, duplicate
ApplicationContext in the context cache in the Spring TestContext
Framework.

This commit uses a TreeSet to ensure that registered active profiles
are both unique and sorted, thereby avoiding cache misses for
semantically identical active profiles configuration on different test
classes.

Closes gh-25973
2020-10-26 11:42:28 +01:00