-
Notifications
You must be signed in to change notification settings - Fork 38.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Support @MockitoBean
in @Configuration
classes
#33934
Comments
We have encountered the same problem. The reason why we define We could use a base class for tests but that goes against the extensible design of JUnit 🤔 |
Everything in the issue queue points to I have nothing agains a better implementation, but this is not a "toy" to play around, neither is the migration "a little thing". For us, this is huge i feeling pushed into a playground in this area feels like being let down. This field needs to be rock solid - and when it is, deprecation can come in. Expamples
there are other issues in the queue pointing at similar, severe issues. I beg you, please roll back the deprecation until the actual target to migrate to is "ready for battle". |
@MockitoBean
on @Configuration
classes
I can confirm I'm running into the same issues when moving from spring boot The test's that are failing due to missing beans are set up almost exactly like @tobias-lippert 's example. With a I also confirmed that adding the mock bean declarations to the test class (as well as alternatively a base abstract test class) directly fixes the problem (like @tobias-lippert mentioned). |
Same here. We also define |
I mentioned this on the Spring Boot repo spring-projects/spring-boot#43282 . |
I'm a Spring Boot maintainer and only speaking for the Boot team below.
There's a tricky balance to strike here. Replacing
IMO, rolling back the deprecation would be counter-productive. Instead, I'd like to try to reassure folks by noting that functionality deprecated in Spring Boot 3.4 won't be going away any time soon. We have Spring Boot 3.5 planned for May 2025 and it won't be removed in that release. Assuming the same pattern as previous releases, OSS support for Spring Boot 3.5 would then be provided until May 2026. Please keep the constructive feedback coming and then address the deprecation either through a suppression or by using an alternative, even if it is one where you feel there's room for improvement. |
The important first
I understand the critic above is harsher in it's tone, but i really try to keep it constructive in the first place (and i gave suggestions / opinions on how to improve it)
I'am following the project rather open-minded and i never heard of the |
I was talking in general terms about our experience with getting a sizeable portion of the user base to try out a new feature, not specifically the introduction of |
That's fair - missed all of those. That one is one me and surely proves you point of not getting substantial feedback if it is not thrown into our faces. Yes, but i have a "but". Use the deprecation as a tool, for a annotation that is used 100+ in the code base (triggering a warning for each), for this specific case, was just not a good choice. For us, it is rather 1000+ and this means, every CI checking testing logs needs massive scrolling, not to talk about proper deprecation warnings which are entirely hidden now. Constructively, i would love to offer something like
So honestly, i have no constructive option on how to fix what has been enforced here while If you ask me, you could have make the entire Do not get me wrong, things move on, break and needs migration. That is what it is and we all have to move. This is fair. I understand, it's probably too late, but at least take my feedback as bring attention to changing such sensible topics. This is not "spring session redis" or "spring security SAML", "jpa" only affecting parts of spring boots ecosystems. This changed affected all ecosystems at once, all of them. And this makes this a sensible one. Thank you for your feedback and comment, really appreciated to at least have a dialog - maybe we do not agree, but still, thank you for being responsive. |
When your policy is to compile with |
Same frustrations here, and it's a bit ironic since both Spring Framework and Spring Boot use those as well 🙂:
Using suppressions tactically here and there is OK, but for non-trivial projects this can easily mean hundreds of suppressions which is really not cool. I understand and agree that it's harder to get quality feedback without doing deprecations, but at the same time there appear to be quite a few common cases that developers rely on and don't have a clear migration path so I feel like this could easily turn out to be a prohibitively expensive upgrade for some projects (which also translates into less feedback). So I'm personally in the camp that would like to see the deprecation rolled back, at least until clear migration path for common use cases is provided. |
@MockitoBean
on @Configuration
classes@MockitoBean
in @Configuration
classes
Team DecisionWe appreciate all of the feedback from the community on this topic, and we understand your concerns regarding the reuse of mock configuration. Unfortunately, we do not have any plans to support In general, the test Bean Override support introduced in Spring Framework 6.2 is designed to be tied directly to test classes, and currently only to fields in test classes. However, we are considering introducing support for declaring In light of the above, I am closing this issue. Regards, Sam |
For those wishing to continue using package com.example;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.mockito.Answers;
import org.mockito.MockSettings;
import org.springframework.boot.test.mock.mockito.MockReset;
import org.springframework.core.annotation.AliasFor;
@SuppressWarnings("removal")
@Target({ ElementType.TYPE, ElementType.FIELD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@org.springframework.boot.test.mock.mockito.MockBean
public @interface MockBean {
/**
* The name of the bean to register or replace. If not specified the name will either
* be generated or, if the mock replaces an existing bean, the existing name will be
* used.
* @return the name of the bean
*/
@AliasFor(attribute = "name", annotation = org.springframework.boot.test.mock.mockito.MockBean.class)
String name() default "";
/**
* The classes to mock. This is an alias of {@link #classes()} which can be used for
* brevity if no other attributes are defined. See {@link #classes()} for details.
* @return the classes to mock
*/
@AliasFor(attribute = "classes", annotation = org.springframework.boot.test.mock.mockito.MockBean.class)
Class<?>[] value() default {};
/**
* The classes to mock. Each class specified here will result in a mock being created
* and registered with the application context. Classes can be omitted when the
* annotation is used on a field.
* <p>
* When {@code @MockBean} also defines a {@code name} this attribute can only contain
* a single value.
* <p>
* If this is the only specified attribute consider using the {@code value} alias
* instead.
* @return the classes to mock
*/
@AliasFor(attribute = "value", annotation = org.springframework.boot.test.mock.mockito.MockBean.class)
Class<?>[] classes() default {};
/**
* Any extra interfaces that should also be declared on the mock. See
* {@link MockSettings#extraInterfaces(Class...)} for details.
* @return any extra interfaces
*/
@AliasFor(attribute = "extraInterfaces", annotation = org.springframework.boot.test.mock.mockito.MockBean.class)
Class<?>[] extraInterfaces() default {};
/**
* The {@link Answers} type to use on the mock.
* @return the answer type
*/
@AliasFor(attribute = "answer", annotation = org.springframework.boot.test.mock.mockito.MockBean.class)
Answers answer() default Answers.RETURNS_DEFAULTS;
/**
* If the generated mock is serializable. See {@link MockSettings#serializable()} for
* details.
* @return if the mock is serializable
*/
@AliasFor(attribute = "serializable", annotation = org.springframework.boot.test.mock.mockito.MockBean.class)
boolean serializable() default false;
/**
* The reset mode to apply to the mock bean. The default is {@link MockReset#AFTER}
* meaning that mocks are automatically reset after each test method is invoked.
* @return the reset mode
*/
@AliasFor(attribute = "reset", annotation = org.springframework.boot.test.mock.mockito.MockBean.class)
MockReset reset() default MockReset.AFTER;
} This allows the deprecation warning to be suppressed in a single place. It should be a drop-in replacement for |
Other solution is to declare mocks as normal beans like this: @TestConfiguration
public class MyTestConfiguration {
@Bean
MyBean myBean() {
return Mockito.mock(MyBean.class);
}
} |
Hi @wilkinsona, I have tried to create a custom annotation for @MockBean as mentioned here, but org.springframework.boot.test.mock.mockito.MockReset enum is used in this custom annotation is also deprecated in version 3.4 . |
@shabbeer4a1 I think the goal is not to provide a permanent solution, but rather help out in the short term with deprecations for the transition period. This annotation is itself annotated with @SuppressWarnings("removal")
@MockBean(classes = Something.class, reset = MockReset.BEFORE) |
@sbrannen please show me how to solve my case with My production code is something like: @Service class A{
public int a() { return 7;}
}
@Service class B{
int b;
public B(A a) { b = a.a();}
} I want test to verify what happens when A returns 8. I followed https://www.baeldung.com/spring-configure-mockbean-components-before-application-start#3-using-mockbean-in-a-nested-test-configuration-class @SpringJUnitConfig
class BTest() {
@TestConfiguration
static class a_returns_8 {
@MockBean A a;
@PostConstruct void let_a_return_8() { when(a.a()).thenReturn(8))}
}
@Autowired B b;
@Test
void b_is_8() {
assertThat(b.b).isEqualTo(8));
} How to implement the test without |
@michaldo, you can implement your @SpringJUnitConfig
class BTest {
@MockitoBean
A a;
@Test
void b_is_8(@Autowired B b) {
assertThat(b.b).isEqualTo(8);
}
@Configuration
@Import({A.class, B.class})
static class Config {
@Autowired
private A a;
@PostConstruct
void let_a_return_8() {
when(this.a.a()).thenReturn(8);
}
}
static class A {
public int a() {
return 7;
}
}
static class B {
private final int b;
public B(A a) {
this.b = a.a();
}
}
} |
Thanks. Bit more complex than previously, isn't it? |
Versions
Spring Boot 3.4.0
Spring Framework 6.2.0
Hi Spring team,
While upgrading our apps to Spring Boot 3.4.0, I've encountered that some of our tests don't start because the application context cannot be created due to a missing bean dependency that should exist as mocked bean.
We define some
MockitoBeans
in a config class annotated with@TestConfiguration
and import this class using@Import
.When I define a MockBean instead, the tests succeed.
You can find an example that reproduces the behavior here: https://github.com/tobias-lippert/spring-mockitobean-test-configuration-import-bug
The test passes on the branch mockbean-working and fails on the branch mockitobean-not-working.
I couldn't find anything in the docs pointing out that this should no longer work. If this is not a bug, but intended behavior please advise how to fix this.
The easiest, but not the prettiest workaround I've found is getting rid of the separate
TestConfigurations
and placing allMockitoBeans
in the actual test class.The text was updated successfully, but these errors were encountered: