Prior to this commit, @MockitoBean could only be declared on fields
within test classes, which prevented developers from being able to
easily reuse mock configuration across a test suite.
With this commit, @MockitoBean is now supported at the type level on
test classes, their superclasses, and interfaces implemented by those
classes. @MockitoBean is also supported on enclosing classes for
@Nested test classes, their superclasses, and interfaces implemented
by those classes, while honoring @NestedTestConfiguration semantics.
In addition, @MockitoBean:
- has a new `types` attribute that can be used to declare the type or
types to mock when @MockitoBean is declared at the type level
- can be declared as a repeatable annotation at the type level
- can be declared as a meta-annotation on a custom composed annotation
which can be reused across a test suite (see the @SharedMocks
example in the reference manual)
To support these new features, this commit also includes the following
changes.
- The `field` property in BeanOverrideHandler is now @Nullable.
- BeanOverrideProcessor has a new `default` createHandlers() method
which is invoked when a @BeanOverride annotation is found at the
type level.
- MockitoBeanOverrideProcessor implements the new createHandlers()
method.
- The internal findHandlers() method in BeanOverrideHandler has been
completely overhauled.
- The @MockitoBean and @MockitoSpyBean section of the reference
manual has been completely overhauled.
Closes gh-33925
As of gh-33847, method and field introspection is included by default
when a type is registered for reflection.
Many methods in ReflectionHintsPredicates are now mostly useless as their
default behavior checks for introspection.
This commit deprecates those methods and promotes instead invocation
variants. During the upgrade, developers should replace it for an
`onType` check if only reflection is required. If they were checking for
invocation, they should use the new 'onXInvocation` method.
Closes gh-34239
Code that compiles against the non-deprecated version does not see the
new constructor that has been introduced. As such, there is no way for
them to migrate to it without resorting to reflection.
This commit restores the deprecated constructor so that people can try
the latest version more easily.
Closes gh-34238
Prior to this commit, the search algorithm used to locate a @TestBean
factory method within a test class hierarchy incorrectly found factory
methods declared in subclasses or nested test classes "below" the class
in which the @TestBean field was declared. This resulted in "duplicate
bean override" failures for @TestBean overrides which are clearly not
duplicates but rather "overrides of an override".
This commit ensures that @TestBean factory method resolution is
consistent in type hierarchies as well as in enclosing class
hierarchies (for @Nested test classes) by beginning the search for a
factory method in the class which declares the @TestBean field.
Closes gh-34204
Prior to this commit, a @BeanOverride (such as @TestBean) for a
specific target bean which was declared in a superclass always took
precedence over a bean override for the same target bean in a subclass,
thereby rendering the bean override configuration in the subclass
useless. In other words, there was no way for a test class to override
a bean override declared in a superclass.
To address that, this commit switches from direct use of
ReflectionUtils.doWithFields() to a custom search algorithm that
traverses the class hierarchy using tail recursion for processing
@BeanOverride fields (delegating now to
ReflectionUtils.doWithLocalFields() in order to continue to benefit
from the caching of declared fields in ReflectionUtils).
Closes gh-34194
This change ensures that a request containing query parameters in the
array format `someArray[]=value` can be bound into a simple array in
constructors, even for cases where the array values don't have nested
properties.
The value resolver is directly called in the constructor case, before
any mutable properties are considered or even cleared (see
`WebDataBinder#adaptEmptyArrayIndices` method). As a result, we need to
accommodate the possibility that the request stores array elements under
the `name[]` key rather than `name`. This change attempts a secondary
lookup with the `[]` suffix if the type is a list or array, and the key
doesn't include an index.
Closes gh-34121
This change ensures that DataBinder can bind constructor with a Map
parameter that has no nested properties, but just simple values like
a String: `someMap[0]=exampleString`.
Integration tests have been added to cover similar cases that use the
ServletRequestDataBinder.
Closes gh-34043
This change removes the `MultiValueMap` nature of `HttpHeaders`, since
it inherits APIs that do not align well with underlying server
implementations. Notably, methods that allows to iterate over the whole
collection of headers are susceptible to artificially introduced
duplicates when multiple casings are used for a given header, depending
on the underlying implementation.
This change includes a dedicated key set implementation to support
iterator-based removal, and either keeps map method implementations that
are relevant or introduces header-focused methods that have a similar
responsibility (like `hasHeaderValues(String, List)` and
`containsHeaderValue(String, String)`).
In order to nudge users away from using an HttpHeaders as a Map, the
`asSingleValueMap` view is deprecated. In order to offer an escape
hatch to users that do make use of the `MultiValueMap` API, a similar
`asMultiValueMap` view is introduced but is immediately marked as
deprecated.
This change also adds map-like but header-focused assertions to
`HttpHeadersAssert`, since it cannot extend `AbstractMapAssert` anymore.
Closes gh-33913
This commit updates the whole Spring Framework codebase to use JSpecify
annotations instead of Spring null-safety annotations with JSR 305
semantics.
JSpecify provides signficant enhancements such as properly defined
specifications, a canonical dependency with no split-package issue,
better tooling, better Kotlin integration and the capability to specify
generic type, array and varargs element null-safety. Generic type
null-safety is not defined by this commit yet and will be specified
later.
A key difference is that Spring null-safety annotations, following
JSR 305 semantics, apply to fields, parameters and return values,
while JSpecify annotations apply to type usages. That's why this
commit moves nullability annotations closer to the type for fields
and return values.
See gh-28797
Prior to this commit, `MockMvc` would support checking for the Servlet
error message as the "response status reason". While this error message
can be driven with the `@ResponseStatus` annotation, this message is not
technically the HTTP status reason listed on the response status line.
This message is provided by the Servlet container in the error page when
the `response.sendError(int, String)` method is used.
This commit adds the missing
`mvc.get().uri("/error/message")).hasErrorMessage("error message")`
assertion to check for this Servlet error message.
Closes gh-34016
It is currently possible for one Bean Override to override another
logically equivalent Bean Override.
For example, a @TestBean can override a @MockitoBean, and vice versa.
In fact, it's also possible for a @MockitoBean to override another
@MockitoBean, for a @TestBean to override a @TestBean, etc.
However, there may be viable use cases for one override overriding
another override. For example, one may have a need to spy on a bean
created by a @TestBean factory method.
In light of that, we do not prohibit one Bean Override from overriding
another Bean Override; however, with this commit we now log a warning
to help developers diagnose issues in case such an override is
unintentional.
For example, given the following test class, where TestConfig registers
a single bean of type MyService named "myService"...
@SpringJUnitConfig(TestConfig.class)
class MyTests {
@TestBean(methodName = "example.TestUtils#createMyService")
MyService testService;
@MockitoBean
MyService mockService;
@Test
void test() {
// ...
}
}
... running that test class results in a log message similar to the
following, which has been formatted for readability.
WARN - Bean with name 'myService' was overridden by multiple handlers:
[
[TestBeanOverrideHandler@44b21f9f
field = example.MyService example.MyTests.testService,
beanType = example.MyService,
beanName = [null],
strategy = REPLACE_OR_CREATE
],
[MockitoBeanOverrideHandler@7ee8130e
field = example.MyService example.MyTests.mockService,
beanType = example.MyService,
beanName = [null],
strategy = REPLACE_OR_CREATE,
reset = AFTER,
extraInterfaces = set[[empty]],
answers = RETURNS_DEFAULTS, serializable = false
]
]
NOTE: The last registered BeanOverrideHandler wins. In the above
example, that means that @MockitoBean overrides @TestBean, resulting
in a Mockito mock for the MyService bean in the test's
ApplicationContext.
Closes gh-34056
Prior to this commit, the Bean Override feature in the Spring
TestContext Framework (for annotations such as @MockitoBean and
@TestBean) silently allowed one bean override to override another
"identical" bean override; however, Spring Boot's @MockBean and
@SpyBean support preemptively rejects identical overrides and throws
an IllegalStateException to signal the configuration error to the user.
To align with the behavior of @MockBean and @SpyBean in Spring Boot,
and to help developers avoid scenarios that are potentially confusing
or difficult to debug, this commit rejects identical bean overrides in
the Spring TestContext Framework.
Note, however, that it is still possible for a bean override to
override a logically equivalent bean override. For example, a
@TestBean can override a @MockitoBean, and vice versa.
Closes gh-34054
To make an analogy to read phenomena for transactional databases, this
commit effectively fixes the "Phantom Read" problem for Bean Overrides.
A phantom read occurs when the BeanOverrideBeanFactoryPostProcessor
retrieves a set of bean names by-type twice and a new bean definition
for a compatible type has been created in the BeanFactory by a
BeanOverrideHandler between the first and second retrieval.
Continue reading for the details...
Prior to this commit, the injection of test Bean Overrides (for
example, when using @MockitoBean) could fail in certain scenarios if
overrides were created for nonexistent beans "by type" without an
explicit name or qualifier. Specifically, if an override for a SubType
was created first, and subsequently an attempt was made to create an
override for a SuperType (where SubType extends SuperType), the
override for the SuperType would "override the override" for the
SubType, effectively removing the override for the SubType.
Consequently, injection of the override instance into the SubType field
would fail with an error message similar to the following.
BeanNotOfRequiredTypeException: Bean named 'Subtype#0' is expected to
be of type 'Subtype' but was actually of type 'Supertype$Mock$XHb7Aspo'
This commit addresses this issue by tracking all generated bean names
(in a generatedBeanNames set) and ensuring that a new bean override
instance is created for the current BeanOverrideHandler if a previous
BeanOverrideHandler already created a bean override instance that now
matches the type required by the current BeanOverrideHandler.
In other words, if the generatedBeanNames set already contains the
beanName that we just found by-type, we cannot "override the override",
because we would lose one of the overrides. Instead, we must create a
new override for the current handler. In the example given above, we
must end up with overrides for both SuperType and SubType.
Closes gh-34025
Includes removal of ManagedBean and javax.annotation legacy support.
Includes AbstractJson(Http)MessageConverter revision for Yasson 3.0.
Includes initial Hibernate ORM 7.0 upgrade.
Closes gh-34011
Closes gh-33750
This commit adapts AOT support in various modules after the RuntimeHints
and related deprecation changes.
`MemberCategory.INTROSPECT_*` hints are now removed and
`MemberCategory.*_FIELDS` are replaced with
`MemberCategory.INVOKE*_FIELDS` when invocation is needed.
Usage of `RuntimeHintsAgent` are also deprecated.
Closes gh-33847
As a follow up to commit 0088b9c7f8, this commit introduces an
integration test which verifies that a spy created via @MockitoSpyBean
using the MockReset.AFTER strategy is not reset between the refresh of
the ApplicationContext and the first use of the spy within a @Test
method.
See gh-33941
See gh-33986
Commit 6c2cba5d8a introduced a regression by inadvertently removing the
MockReset strategy comparison when resetting @MockitoBean and
@MockitoSpyBean mocks.
This commit reinstates the MockReset strategy check and introduces
tests for this feature.
Closes gh-33941
This commit upgrades our Mock Servlet classes for Servlet 6.1 support:
* the read/write `ByteBuffer` variants for `ServletInputStream` and
`ServletOutputStream` were not added as the default implementation
matches well the testing use case.
* Implement the session accessor with a simple lambda. Our mocks do not
simulate the scheduling of request/response processing on different
threads.
* Ensure that the response content length can only be written before the
response is committed. Calling those methods after commit is a no-op,
per specification.
Closes gh-33749
This commit makes it clear that there are no visibility requirements
for @TestBean fields or factory methods as well as @MockitoBean or
@MockitoSpyBean fields.
Closes gh-33923
This commit updates the Spring Framework baseline for the Servlet, JSP
and WebSocket APIs.
This also removes the previously deprecated APIs in JSP `PageContext`
and guards against the deprecation of the `PushBuilder` API.
See gh-33918
This commit introduces a TestBeanReflectiveProcessor that registers
GraalVM native image reflection hints for a fully-qualified method name
configured via @TestBean.
Closes gh-33836
Prior to this commit, the static factory methods in MockReset (such as
MockReset.before() and MockReset.after()) could only be applied to
beans within the ApplicationContext if the test class declared at least
one field annotated with either @MockitoBean or @MockitoSpyBean.
However, the Javadoc states that it should be possible to apply
MockReset directly to any mock in the ApplicationContext using the
static methods in MockReset.
To address that, this commit reworks the "enabled" logic in
MockitoResetTestExecutionListener as follows.
- We no longer check for the presence of annotations from the
org.springframework.test.context.bean.override.mockito package to
determine if MockReset is enabled.
- Instead, we now rely on a new isEnabled() method to determine if
MockReset is enabled.
The logic in the isEnabled() method still relies on the mockitoPresent
flag as an initial check; however, mockitoPresent only determines if
Mockito is present in the classpath. It does not determine if Mockito
can actually be used. For example, it does not detect if the necessary
reachability metadata has been registered to use Mockito within a
GraalVM native image.
To address that last point, the isEnabled() method performs an
additional check to determine if Mockito can be used in the current
environment. Specifically, it invokes Mockito.mockingDetails().isMock()
which in turn initializes core Mockito classes without actually
attempting to create a mock. If that fails, that means that Mockito
cannot actually be used in the current environment, which typically
indicates that GraalVM reachability metadata has not been registered
for the org.mockito.plugins.MockMaker in use (such as the
ProxyMockMaker).
In addition, isEnabled() lazily determines if Mockito can be
initialized, since attempting to detect that during static
initialization results in a GraalVM native image error stating that
Mockito internals were "unintentionally initialized at build time".
If Mockito cannot be initialized, MockitoResetTestExecutionListener
logs a DEBUG level message providing access to the corresponding stack
trace, and MockReset support is disabled.
Closes gh-33829
This commit verifies that MockReset.before() and MockReset.after() are
supported for beans within the ApplicationContext.
However, the test class must declare a field annotated with either
@MockitoBean or @MockitoSpyBean in order for the MockReset feature to
be triggered.
See gh-33742
Spring Boot has honored @Primary for selecting which candidate bean
@MockBean and @SpyBean should mock or spy since Spring Boot 1.4.3;
however, the support for @Primary was not ported from Spring Boot to
Spring Framework's new Bean Overrides feature in the TestContext
framework.
To address that, this commit introduces support for @Primary for
selecting bean overrides -- for example, for annotations such as
@TestBean, @MockitoBean, and @MockitoSpyBean.
See https://github.com/spring-projects/spring-boot/issues/7621
Closes gh-33819
This commit introduces integration tests which verify that Bean
Overrides (for example, @MockitoBean and @MockitoSpyBean) can select
a single candidate bean to override when there are multiple candidates
that match the required type.
To "select" the desired bean, these tests rely on one of the following.
- explicit bean name in the bean override annotation
- explicit @Qualifier on the bean override field
- explicit @Primary on one of the candidate beans
However, the @Primary tests are currently @Disabled until @Primary
is honored in the Spring TestContext Framework.
See gh-33742
Previously, we only looked at the OBJECT_TYPE_ATTRIBUTE on a
FactoryBean's bean definition; however this does not work for
situations where the information is provided by the definition's target
type rather than the attribute.
Rather than manually considering the target type in addition to the
existing consideration of the attribute, we now ask the BeanFactory for
the type that will be produced by the FactoryBean instead.
See https://github.com/spring-projects/spring-boot/issues/40234
Closes gh-33811
Co-authored-by: Andy Wilkinson <andy.wilkinson@broadcom.com>
This commit introduces a test which verifies that @MockitoSpyBean on a
field with generics can be used to replace an existing bean with
matching generics that's produced by a FactoryBean that's
programmatically registered via an ImportBeanDefinitionRegistrar.
However, the test is currently @Disabled until the fix for
https://github.com/spring-projects/spring-boot/issues/40234 has been
ported to Spring Framework.
See gh-33742
In gh-33602, we introduced strict singleton enforcement for bean
overrides -- for example, for @MockitoBean, @TestBean, etc. However,
the use of BeanFactory#isSingleton(beanName) can result in a
BeanCreationException for certain beans, such as a Spring Data JPA
FactoryBean for a JpaRepository.
In light of that, this commit relaxes the singleton enforcement in
BeanOverrideBeanFactoryPostProcessor by only checking the result of
BeanDefinition#isSingleton() for existing bean definitions.
This commit also updates the Javadoc and reference documentation to
reflect the status quo.
See gh-33602
Closes gh-33800
This commit removes the proxyTargetAware attribute from @MockitoSpyBean
while keeping the underlying feature in tact (i.e., transparent
verification for spies created via @MockitoSpyBean).
Closes gh-33775
Prior to this commit, SpringAopBypassingVerificationStartedListener
provided partial support for transparent verification for Mockito spies
created via @MockitoSpyBean when the spy is wrapped in a Spring AOP
proxy. However, attempting to actually verify invocations for a spy
resulted in an exception from Mockito since MockUtil.isMock() returned
false in such scenarios.
This commit addresses that by introducing a SpringMockResolver that
resolves mocks by walking the Spring AOP proxy chain until the target
or a non-static proxy is found.
SpringMockResolver is automatically registered whenever the spring-test
JAR is on the classpath, allowing Mockito to transparently resolve mocks
wrapped in Spring AOP proxies.
Closes gh-33774
Prior to this commit, OverrideMetadata was the only public type in the
org.springframework.test.context.bean.override package whose name did
not start with BeanOverride. In addition, an OverrideMetadata component
plays multiple roles in addition to serving as a holder for metadata.
This commit therefore renames OverrideMetadata to BeanOverrideHandler.
In addition, this commit updates the affected documentation and renames
the following related methods in the Bean Override support.
- BeanOverrideHandler: createOverride() -> createOverrideInstance()
- BeanOverrideHandler: track() -> trackOverrideInstance()
- BeanOverrideProcessor: createMetadata() -> createHandler()
- BeanOverrideContextCustomizer: getMetadata() -> getBeanOverrideHandlers()
- BeanOverrideRegistrar: registerNameForMetadata() -> registerBeanOverrideHandler()
- BeanOverrideRegistrar: markWrapEarly() -> registerWrappingBeanOverrideHandler()
Closes gh-33702
This change remove the support for Mockito annotations, `MockitoSession`
and opening/closing of mocks that was inherited from Boot's `@MockBean`
support, as well as the switch to `MockitoSession` made in 1c893e6.
Attempting to take responsability for things Mockito's own JUnit
Jupiter extension does better is not ideal, and we found it leads to
several corner cases which make `SpringExtension` and `MockitoExtension`
incompatible in the current approach.
Instead, this change refocuses our Mockito bean overriding support
exclusively on aspects specific to the Framework. `MockitoExtension`
will thus be usable in conjunction with `SpringExtension` if one needs
to use `@Captor`/`@InitMocks`/`@Mock`/`@Spy` or other Mockito utilities.
See gh-33318
Closes gh-33692
Prior to this commit, the MockitoResetTestExecutionListener failed to
reset mocks created via @MockitoBean if the @MockitoBean field was
declared in an enclosing class for a @Nested test class. In addition,
the MockitoSession was not properly managed by the
MockitoTestExecutionListener.
This commit addresses those issue as follows.
1) The hasMockitoAnnotations() utility method has been overhauled so
that it finds Mockito annotations not only on the current test class
and on fields of the current test class but also on interfaces,
superclasses, and enclosing classes for @Nested test classes as well
as on fields of superclasses and enclosing classes.
That allows the MockitoResetTestExecutionListener to properly detect
that it needs to reset mocks for fields declared in enclosing classes
for @Nested classes.
2) MockitoTestExecutionListener has been revised so that it only
initializes a MockitoSession before each test method and closes the
MockitoSession after each test method. In addition, it now only manages
the MockitoSession when hasMockitoAnnotations() returns true for the
current test class (which may be a @Nested test class). Furthermore,
it no longer attempts to initialize a MockitoSession during the
prepareTestInstance() callback since that results in an
UnfinishedMockingSessionException for a @Nested test class due to the
fact that a MockitoSession was already created for the current thread
for the enclosing test class.
Closes gh-33676
This commit improves the user experience for common use cases by
introducing new `value` attributes in @MockitoBean and
@MockitoSpyBean that are aliases for the existing `name` attributes.
For example, this allows developers to declare
@MockitoBean("userService") instead of @MockitoBean(name =
"userService"), analogous to the existing name/value alias support in
@TestBean.
Closes gh-33680
Based on feedback from the Spring Boot team, we have decided to change
the default values for the enforceOverride flags in @TestBean and
@MockitoBean from true to false.
Closes gh-33613
This commit simplifies the field injection logic for Bean Overrides in
order to align with the semantics of the core container and the Spring
TestContext Framework.
Closes gh-33677
Instead, MockitoResetTestExecutionListener is now only enabled if the
current test class uses Mockito annotations or Mockito-related
annotations in spring-test.
See gh-32933
This commit introduces a BeanOverrideReflectiveProcessor which
registers runtime hints for any BeanOverrideProcessor configured
via @BeanOverride.
See gh-32933
Prior to this commit, AOT processing failed for tests that made use of
the Bean Override feature to "override" a nonexistent bean. The reason
is that we register a "pseudo" bean definition as a placeholder for a
nonexistent bean, and our AOT support cannot automatically convert that
"pseudo" bean definition to a functional bean definition for use at AOT
runtime.
To address that, this commit skips registration of "pseudo" bean
definitions during AOT processing, and by doing so we enable the JVM
runtime and AOT runtime to operate with the same semantics.
See gh-32933
Prior to this commit, AOT processing failed for tests that made use of
the Bean Override feature, since the Set<OverrideMetadata> constructor
argument configured in the bean definition for the
BeanOverrideBeanFactoryPostProcessor cannot be properly processed by
our AOT support. The reason is that each OverrideMetadata instance is
effectively an arbitrary object graph that cannot be automatically
converted to a functional bean definition for use at AOT runtime.
To address that, this commit registers Bean Override infrastructure
beans as manual singletons instead of via bean definitions with the
infrastructure role.
See gh-32933
This commit simplifies the implementation of
BeanOverrideTestExecutionListener by introducing a static
injectFields() utility method and removing the use of BiConsumers,
records, and duplicated code.
This commit also introduces Javadoc for all methods in
BeanOverrideTestExecutionListener.
Closes gh-33660
Prior to this commit, ApplicationContext caching support was broken if
two Bean Override fields declared the same annotations but in a
different order.
This commit fixes that by switching to Set semantics for the
annotations declared on a Bean Override field.
Closes gh-33633
Prior to this commit, BeanOverrideBeanFactoryPostProcessor replaced
existing bean definitions with "pseudo" bean definitions; however, that
is unnecessary. An existing BeanDefinition is suitable as-is and does
not need to be replaced with a pseudo/fake definition.
To address that, this commit reregisters an existing bean definition
and only registers a new bean definition when creating a bean
definition for a nonexistent bean.
As a side effect, we no longer need to copy primary and fallback flags.
Closes gh-33627
Prior to this commit, @MockitoBean could be used to either create or
replace a bean definition, but @TestBean could only be used to replace
a bean definition.
However, Bean Override implementations should require the presence of
an existing bean definition by default (i.e. literally "override" by
default), while giving the user the option to have a new bean
definition created if desired.
To address that, this commit introduces a new `enforceOverride`
attribute in @TestBean and @MockitoBean that defaults to true but
allows the user to decide if it's OK to create a bean for a nonexistent
bean definition.
Closes gh-33613
Prior to this commit, a non-singleton FactoryBean was silently replaced
by a singleton bean. In addition, bean definitions for prototype-scoped
and custom-scoped beans were replaced by singleton bean definitions
that were incapable of creating the desired bean instance. For example,
if the bean type of the original bean definition was a concrete class,
an attempt was made to invoke the default constructor which either
succeeded with undesirable results or failed with an exception if the
bean type did not have a default constructor. If the bean type of the
original bean definition was an interface or a FactoryBean that claimed
to create a bean of a certain interface type, an attempt was made to
instantiate the interface which always failed with a
BeanCreationException.
To address the aforementioned issues, this commit reworks the logic in
BeanOverrideBeanFactoryPostProcessor so that an exception is thrown
whenever an attempt is made to override a non-singleton bean.
Closes gh-33602
The tests introduced in this commit reveal the following issues in our
Bean Override support.
- If a FactoryBean signals it does not manage a singleton, the Bean
Override support silently replaces it with a singleton.
- An attempt to override a prototype-scoped bean or a bean configured
with a custom scope results in one of the following.
- If the bean type of the original bean definition is a concrete
class, an attempt will be made to invoke the default constructor
which will either succeed with undesirable results or fail with an
exception if the bean type does not have a default constructor.
- If the bean type of the original bean definition is an interface or
a FactoryBean that claims to create a bean of a certain interface
type, an attempt will be made to instantiate the interface which
will always fail with a BeanCreationException.
In order to allow third parties (for example, Spring Boot) to ensure
that a DynamicPropertyRegistrarBeanInitializer has been registered in
an ApplicationContext which has not been customized by the
DynamicPropertiesContextCustomizer, this commit converts
DynamicPropertyRegistrarBeanInitializer to a public API for use in such
special use cases.
Closes gh-33593
This commit introduces example support for a custom @EasyMockBean
annotation that allows tests to use EasyMock as the mocking framework
for bean overrides in a test's ApplicationContext.
The point of this exercise is to ensure that it is possible for third
parties to introduce bean override support for mocking frameworks other
than Mockito, and that they can do so with the APIs currently in place.
Closes gh-33562
Spring Boot's testing support registers a DynamicPropertyRegistry as a
bean in the ApplicationContext, which conflicts with the
DynamicPropertyRegistry registered as a bean by the Spring TestContext
Framework (TCF) since Spring Framework 6.2 M2.
To avoid that conflict and to improve the user experience for Spring's
testing support, this commit introduces a DynamicPropertyRegistrar API
to replace the DynamicPropertyRegistry bean support.
Specifically, the TCF no longer registers a DynamicPropertyRegistry as
a bean in the ApplicationContext.
Instead, users can now register custom implementations of
DynamicPropertyRegistrar as beans in the ApplicationContext, and the
DynamicPropertiesContextCustomizer now registers a
DynamicPropertyRegistrarBeanInitializer which eagerly initializes
DynamicPropertyRegistrar beans and invokes their accept() methods with
an appropriate DynamicPropertyRegistry.
In addition, a singleton DynamicValuesPropertySource is created and
registered with the Environment for use in
DynamicPropertiesContextCustomizer and
DynamicPropertyRegistrarBeanInitializer, which allows
@DynamicPropertySource methods and DynamicPropertyRegistrar beans to
transparently populate the same DynamicValuesPropertySource.
Closes gh-33501
This commit exposes the unexpanded URI template used to build a
MockHttpServletRequest. This allows MockMvc users to retrieve that
information, in consistency with ExchangeResult in WebTestClient.
Closes gh-33509
Prior to this commit, when ReflectionTestUtils was used to invoke a
method on a CGLIB proxy, the invocation was always performed directly
on the proxy. Consequently, if the method was not proxied/intercepted
by the CGLIB proxy -- for example, if the method was final or
effectively private -- the invoked method could not operate on the
state of the target object or interact with other private methods in
the target object.
With this commit, if the supplied target object is a CGLIB proxy which
does not intercept the method, the proxy will be unwrapped allowing the
method to be invoked directly on the ultimate target of the proxy.
Closes gh-33429
This commit applies the same kind of processing for
Void.class element type in the ParameterizedTypeReference
variant of WebTestClient.ResponseSpec#returnResult than
in the Class variant.
Closes gh-33389
This commit changes the way the `MockitoTestExecutionListener` sets up
mockito, now using the `MockitoSession` feature. Additionally, stubbing
now defaults to a STRICT mode which can be overruled with a newly
introduced annotation: `@MockitoBeanSettings`.
Closes gh-33318
Follow-up to d2225c, which broke Boot tests because the ServletContext can
be the one of the embedded Servlet container if initializing a live server
and as well as MockMvc (e.g. via `@AutoConfigureMockMvc`).
See gh-33252
This commit makes sure to check first if
DynamicPropertySourceBeanInitializer has been registered before trying
to register it.
When running with AOT optimizations, the bean definition has been
contributed so there is no need to register it again when the context
customizer runs.
Closes gh-33272
Previous to this commit, MockHttpServletRequestBuilder was not binary
compatible as its methods had moved to a parent class with a generic
argument on the return type. MockMultipartHttpServletRequestBuilder
was also not source compatible as it no longed extended from
MockHttpServletRequestBuilder.
Both these changes were introduced to allow the AssertJ support to
expose builders that implement an extra AssertJ interface, without
copying the features the builders provide.
This commit restore compatibility. For MockHttpServletRequestBuilder
we simply override all methods that returns the generic type into
the resolved type.
MockMultipartHttpServletRequestBuilder is more involved. Because we
need to extend from MockHttpServletRequestBuilder, we have no other
choice than duplicating the code. For now, the abstract builder for
multipart is only used by the AssertJ support, but we can revisit this
again in a major release.
Closes gh-33229
This application/javascript MIME type is deprecated.
This commit therefore changes the MIME type mapping for *.js files from
application/javascript to text/javascript in order to align with
industry standards.
Closes gh-33197
This commit introduces an abstraction that allows to convert HTTP
inputs to a data type based on a set of HttpMessageConverter.
Previously, the AssertJ integration was finding the first converter
that is able to convert JSON to a Map (and vice-versa) and used that
in its API. With the introduction of SmartHttpMessageConverter, exposing
a specific converter is fragile.
The added abstraction allows for converting other kind of input than
JSON if we need to do that in the future.
Closes gh-33148
Prior to this commit, paths configured via the scripts attribute in
@Sql were required to be final paths without dynamic placeholders;
however, being able to make script paths dependent on the current
environment can be useful in certain testing scenarios.
This commit introduces support for property placeholders (${...}) in
@Sql script paths which will be replaced by properties available in
the Environment of the test's ApplicationContext.
Closes gh-33114
Prior to this commit, @TestBean factory methods had to be defined in
the test class, one of its superclasses, or in an implemented
interface. However, users may wish to define common factory methods in
external classes that can be shared easily across multiple test classes
simply by referencing an external method via a fully-qualified method
name.
To address that, this commit introduces support for referencing a
@TestBean factory method via its fully-qualified method name following
the syntax <fully-qualified class name>#<method name>.
Closes gh-33125
This commit makes MockHttpServletResponse consistent with the other
parts of the framework where the body of a response is read as an UTF-8
String when the content type is application/json or similar, overriding
the ISO-8859-1 default Servlet encoding.
Closes gh-33019
This commit improves the handling of asynchronous requests by offering
a way to opt-in for the raw async result. This provides first class
support for asserting a request that might still be in process as well
as the asyncResult, if necessary.
See gh-33040
This commit makes asynchronous requests first class by providing a
MvcTestResult that represents the final, completed, state of a request
by default. Previously, the result was an intermediate step that may
require an ASYNC dispatch to be fully usable. Now it is de facto
immutable.
To make things a bit more explicit, an `.exchange(Duration)` method has
been added to provide a dedicated time to wait. The default applies a
default timeout that is consistent with what MVcResult#getAsyncResult
does.
Given that we apply the ASYNC dispatch automatically, the intermediate
response is no longer available by default. As a result, the asyncResult
is not available for assertions.
As always, it is possible to use plain MockMvc by using the `perform`
method that takes the regular RequestBuilder as an input. When this
method is invoked, no asynchronous handling is done.
Closes gh-33040
This commit simplifies the package private constructors on those two
builders now that the URI can be specified by dedicated builder methods.
Closes gh-33062
File uploads with MockMvc require a separate
MockHttpServletRequestBuilder implementation. This commit applies the
same change to support AssertJ on this builder, but for the multipart
version.
Any request builder can now use `multipart()` to "down cast" to a
dedicated multipart request builder that contains the settings
configured thus far.
Closes gh-33027
This commit simplifies assertions on MockMvc requests that have failed
to process. A now general hasFailed/doesNotHaveFailed/failure provides
the necessary to assert the exception.
Any attempt to access anything from the result with an unresolved
exception still fails as before.
Closes gh-33060