diff --git a/spring-test/src/test/java/org/springframework/test/context/bean/override/mockito/MockitoBeanForBeanFactoryIntegrationTests.java b/spring-test/src/test/java/org/springframework/test/context/bean/override/mockito/MockitoBeanForBeanFactoryIntegrationTests.java index c7e6a3ca71d..5c86ef4312b 100644 --- a/spring-test/src/test/java/org/springframework/test/context/bean/override/mockito/MockitoBeanForBeanFactoryIntegrationTests.java +++ b/spring-test/src/test/java/org/springframework/test/context/bean/override/mockito/MockitoBeanForBeanFactoryIntegrationTests.java @@ -18,6 +18,7 @@ package org.springframework.test.context.bean.override.mockito; import java.util.concurrent.atomic.AtomicBoolean; +import org.junit.jupiter.api.Order; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.FactoryBean; @@ -44,17 +45,24 @@ class MockitoBeanForBeanFactoryIntegrationTests { @Autowired private ApplicationContext applicationContext; + @Order(1) @Test void beanReturnedByFactoryIsMocked() { TestBean bean = this.applicationContext.getBean(TestBean.class); assertThat(bean).isSameAs(this.testBean); - when(testBean.hello()).thenReturn("amock"); + when(this.testBean.hello()).thenReturn("amock"); assertThat(bean.hello()).isEqualTo("amock"); assertThat(TestFactoryBean.USED).isFalse(); } + @Order(2) + @Test + void beanReturnedByFactoryIsReset() { + assertThat(this.testBean.hello()).isNull(); + } + @Configuration(proxyBeanMethods = false) static class Config { diff --git a/spring-test/src/test/java/org/springframework/test/context/bean/override/mockito/MockitoBeanWithResetIntegrationTests.java b/spring-test/src/test/java/org/springframework/test/context/bean/override/mockito/MockitoBeanWithResetIntegrationTests.java new file mode 100644 index 00000000000..f216ba6e919 --- /dev/null +++ b/spring-test/src/test/java/org/springframework/test/context/bean/override/mockito/MockitoBeanWithResetIntegrationTests.java @@ -0,0 +1,116 @@ +/* + * Copyright 2002-2024 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.test.context.bean.override.mockito; + +import org.junit.jupiter.api.Order; +import org.junit.jupiter.api.Test; + +import org.springframework.beans.factory.FactoryBean; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.lang.Nullable; +import org.springframework.test.context.bean.override.example.ExampleService; +import org.springframework.test.context.bean.override.example.FailingExampleService; +import org.springframework.test.context.bean.override.example.RealExampleService; +import org.springframework.test.context.junit.jupiter.SpringJUnitConfig; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.doReturn; + +/** + * Integration tests for {@link MockitoBean} that validate automatic reset + * of stubbing. + * + * @author Simon Baslé + * @since 6.2 + */ +@SpringJUnitConfig +public class MockitoBeanWithResetIntegrationTests { + + @MockitoBean(reset = MockReset.BEFORE) + ExampleService service; + + @MockitoBean(reset = MockReset.BEFORE) + FailingExampleService failingService; + + @Order(1) + @Test + void beanFirstEstablishingMock(ApplicationContext ctx) { + ExampleService mock = ctx.getBean("service", ExampleService.class); + doReturn("Mocked hello").when(mock).greeting(); + + assertThat(this.service.greeting()).isEqualTo("Mocked hello"); + } + + @Order(2) + @Test + void beanSecondEnsuringMockReset(ApplicationContext ctx) { + assertThat(ctx.getBean("service")).isNotNull().isSameAs(this.service); + + assertThat(this.service.greeting()).as("not stubbed").isNull(); + } + + @Order(3) + @Test + void factoryBeanFirstEstablishingMock(ApplicationContext ctx) { + FailingExampleService mock = ctx.getBean(FailingExampleService.class); + doReturn("Mocked hello").when(mock).greeting(); + + assertThat(this.failingService.greeting()).isEqualTo("Mocked hello"); + } + + @Order(4) + @Test + void factoryBeanSecondEnsuringMockReset(ApplicationContext ctx) { + assertThat(ctx.getBean("factory")).isNotNull().isSameAs(this.failingService); + + assertThat(this.failingService.greeting()).as("not stubbed") + .isNull(); + } + + static class FailingExampleServiceFactory implements FactoryBean { + @Nullable + @Override + public FailingExampleService getObject() { + return new FailingExampleService(); + } + + @Nullable + @Override + public Class getObjectType() { + return FailingExampleService.class; + } + } + + @Configuration + static class Config { + + @Bean("service") + ExampleService bean1() { + return new RealExampleService("Production hello"); + } + + @Bean("factory") + @Qualifier("factory") + FailingExampleServiceFactory factory() { + return new FailingExampleServiceFactory(); + } + } + +} diff --git a/spring-test/src/test/java/org/springframework/test/context/bean/override/mockito/MockitoSpyBeanForBeanFactoryIntegrationTests.java b/spring-test/src/test/java/org/springframework/test/context/bean/override/mockito/MockitoSpyBeanForBeanFactoryIntegrationTests.java index dfc1b9f949d..742360ea08c 100644 --- a/spring-test/src/test/java/org/springframework/test/context/bean/override/mockito/MockitoSpyBeanForBeanFactoryIntegrationTests.java +++ b/spring-test/src/test/java/org/springframework/test/context/bean/override/mockito/MockitoSpyBeanForBeanFactoryIntegrationTests.java @@ -16,6 +16,7 @@ package org.springframework.test.context.bean.override.mockito; +import org.junit.jupiter.api.Order; import org.junit.jupiter.api.Test; import org.mockito.Mockito; @@ -28,6 +29,7 @@ import org.springframework.test.context.bean.override.mockito.MockitoBeanForBean import org.springframework.test.context.junit.jupiter.SpringJUnitConfig; import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.doReturn; /** * Test {@link MockitoSpyBean @MockitoSpyBean} for a factory bean configuration. @@ -46,13 +48,25 @@ class MockitoSpyBeanForBeanFactoryIntegrationTests { @Autowired private ApplicationContext applicationContext; + @Order(1) @Test void beanReturnedByFactoryIsSpied() { TestBean bean = this.applicationContext.getBean(TestBean.class); assertThat(this.testBean).as("injected same").isSameAs(bean); assertThat(bean.hello()).isEqualTo("hi"); - Mockito.verify(bean).hello(); + + doReturn("sp-hi").when(this.testBean).hello(); + + assertThat(bean.hello()).as("after stubbing").isEqualTo("sp-hi"); + Mockito.verify(bean, Mockito.times(2)).hello(); + } + + @Order(2) + @Test + void beanReturnedByFactoryIsReset() { + assertThat(this.testBean.hello()) + .isNotEqualTo("sp-hi"); } @Test diff --git a/spring-test/src/test/java/org/springframework/test/context/bean/override/mockito/MockitoSpyBeanWithResetIntegrationTests.java b/spring-test/src/test/java/org/springframework/test/context/bean/override/mockito/MockitoSpyBeanWithResetIntegrationTests.java new file mode 100644 index 00000000000..995af78e492 --- /dev/null +++ b/spring-test/src/test/java/org/springframework/test/context/bean/override/mockito/MockitoSpyBeanWithResetIntegrationTests.java @@ -0,0 +1,119 @@ +/* + * Copyright 2002-2024 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.test.context.bean.override.mockito; + +import org.junit.jupiter.api.Order; +import org.junit.jupiter.api.Test; + +import org.springframework.beans.factory.FactoryBean; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.lang.Nullable; +import org.springframework.test.context.bean.override.example.ExampleService; +import org.springframework.test.context.bean.override.example.FailingExampleService; +import org.springframework.test.context.bean.override.example.RealExampleService; +import org.springframework.test.context.junit.jupiter.SpringJUnitConfig; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatIllegalStateException; +import static org.mockito.Mockito.doReturn; + +/** + * Integration tests for {@link MockitoSpyBean} that validate automatic reset + * of stubbing. + * + * @author Simon Baslé + * @since 6.2 + */ +@SpringJUnitConfig +public class MockitoSpyBeanWithResetIntegrationTests { + + @MockitoSpyBean(reset = MockReset.BEFORE) + ExampleService service; + + @MockitoSpyBean(reset = MockReset.BEFORE) + FailingExampleService failingService; + + @Order(1) + @Test + void beanFirstEstablishingStub(ApplicationContext ctx) { + ExampleService spy = ctx.getBean("service", ExampleService.class); + doReturn("Stubbed hello").when(spy).greeting(); + + assertThat(this.service.greeting()).isEqualTo("Stubbed hello"); + } + + @Order(2) + @Test + void beanSecondEnsuringStubReset(ApplicationContext ctx) { + assertThat(ctx.getBean("service")).isNotNull().isSameAs(this.service); + + assertThat(this.service.greeting()).as("not stubbed") + .isEqualTo("Production hello"); + } + + @Order(3) + @Test + void factoryBeanFirstEstablishingStub(ApplicationContext ctx) { + FailingExampleService spy = ctx.getBean(FailingExampleService.class); + doReturn("Stubbed hello").when(spy).greeting(); + + assertThat(this.failingService.greeting()).isEqualTo("Stubbed hello"); + } + + @Order(4) + @Test + void factoryBeanSecondEnsuringStubReset(ApplicationContext ctx) { + assertThat(ctx.getBean("factory")).isNotNull().isSameAs(this.failingService); + + assertThatIllegalStateException().isThrownBy(this.failingService::greeting) + .as("not stubbed") + .withMessage("Failed"); + } + + static class FailingExampleServiceFactory implements FactoryBean { + @Nullable + @Override + public FailingExampleService getObject() { + return new FailingExampleService(); + } + + @Nullable + @Override + public Class getObjectType() { + return FailingExampleService.class; + } + } + + @Configuration + static class Config { + + @Bean("service") + ExampleService bean1() { + return new RealExampleService("Production hello"); + } + + @Bean("factory") + @Qualifier("factory") + FailingExampleServiceFactory factory() { + return new FailingExampleServiceFactory(); + } + } + +}