Skip to content

Commit 7148b28

Browse files
committed
Integration test Bean Override support for multiple candidate beans
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
1 parent 1255bd1 commit 7148b28

6 files changed

+532
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
/*
2+
* Copyright 2012-2024 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.test.context.bean.override.mockito.integration;
18+
19+
import org.junit.jupiter.api.Test;
20+
import org.mockito.MockingDetails;
21+
import org.mockito.mock.MockCreationSettings;
22+
23+
import org.springframework.beans.factory.annotation.Autowired;
24+
import org.springframework.context.annotation.Bean;
25+
import org.springframework.context.annotation.Configuration;
26+
import org.springframework.context.annotation.Import;
27+
import org.springframework.test.context.bean.override.example.ExampleGenericServiceCaller;
28+
import org.springframework.test.context.bean.override.example.IntegerExampleGenericService;
29+
import org.springframework.test.context.bean.override.example.StringExampleGenericService;
30+
import org.springframework.test.context.bean.override.mockito.MockitoBean;
31+
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
32+
33+
import static org.assertj.core.api.Assertions.assertThat;
34+
import static org.mockito.BDDMockito.given;
35+
import static org.mockito.BDDMockito.then;
36+
import static org.mockito.Mockito.mockingDetails;
37+
38+
/**
39+
* Tests that {@link MockitoBean @MockitoBean} can be used to mock a bean when
40+
* there are multiple candidates and an explicit bean name is supplied to select
41+
* one of the candidates.
42+
*
43+
* @author Sam Brannen
44+
* @author Phillip Webb
45+
* @since 6.2
46+
* @see MockitoBeanWithMultipleExistingBeansAndExplicitQualifierIntegrationTests
47+
* @see MockitoBeanWithMultipleExistingBeansAndOnePrimaryIntegrationTests
48+
*/
49+
@SpringJUnitConfig
50+
class MockitoBeanWithMultipleExistingBeansAndExplicitBeanNameIntegrationTests {
51+
52+
@MockitoBean("stringService")
53+
StringExampleGenericService mock;
54+
55+
@Autowired
56+
ExampleGenericServiceCaller caller;
57+
58+
59+
@Test
60+
void test() {
61+
MockingDetails mockingDetails = mockingDetails(mock);
62+
MockCreationSettings<?> mockSettings = mockingDetails.getMockCreationSettings();
63+
assertThat(mockingDetails.isMock()).as("is mock").isTrue();
64+
assertThat(mockSettings.getMockName()).as("mock name").hasToString("stringService");
65+
66+
given(mock.greeting()).willReturn("mocked");
67+
assertThat(caller.sayGreeting()).isEqualTo("I say mocked 123");
68+
then(mock).should().greeting();
69+
}
70+
71+
72+
@Configuration(proxyBeanMethods = false)
73+
@Import({ ExampleGenericServiceCaller.class, IntegerExampleGenericService.class })
74+
static class Config {
75+
76+
@Bean
77+
StringExampleGenericService one() {
78+
return new StringExampleGenericService("one");
79+
}
80+
81+
@Bean
82+
// "stringService" matches the constructor argument name in ExampleGenericServiceCaller
83+
StringExampleGenericService stringService() {
84+
return new StringExampleGenericService("two");
85+
}
86+
}
87+
88+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
/*
2+
* Copyright 2012-2024 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.test.context.bean.override.mockito.integration;
18+
19+
import org.junit.jupiter.api.Test;
20+
import org.mockito.MockingDetails;
21+
import org.mockito.mock.MockCreationSettings;
22+
23+
import org.springframework.beans.factory.annotation.Autowired;
24+
import org.springframework.beans.factory.annotation.Qualifier;
25+
import org.springframework.context.annotation.Bean;
26+
import org.springframework.context.annotation.Configuration;
27+
import org.springframework.context.annotation.Import;
28+
import org.springframework.test.context.bean.override.example.ExampleGenericServiceCaller;
29+
import org.springframework.test.context.bean.override.example.IntegerExampleGenericService;
30+
import org.springframework.test.context.bean.override.example.StringExampleGenericService;
31+
import org.springframework.test.context.bean.override.mockito.MockitoBean;
32+
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
33+
34+
import static org.assertj.core.api.Assertions.assertThat;
35+
import static org.mockito.BDDMockito.given;
36+
import static org.mockito.BDDMockito.then;
37+
import static org.mockito.Mockito.mockingDetails;
38+
39+
/**
40+
* Tests that {@link MockitoBean @MockitoBean} can be used to mock a bean when
41+
* there are multiple candidates and a {@link Qualifier @Qualifier} is supplied
42+
* to select one of the candidates.
43+
*
44+
* @author Sam Brannen
45+
* @author Phillip Webb
46+
* @since 6.2
47+
* @see MockitoBeanWithMultipleExistingBeansAndExplicitBeanNameIntegrationTests
48+
* @see MockitoBeanWithMultipleExistingBeansAndOnePrimaryIntegrationTests
49+
*/
50+
@SpringJUnitConfig
51+
class MockitoBeanWithMultipleExistingBeansAndExplicitQualifierIntegrationTests {
52+
53+
@Qualifier("stringService")
54+
@MockitoBean
55+
StringExampleGenericService mock;
56+
57+
@Autowired
58+
ExampleGenericServiceCaller caller;
59+
60+
61+
@Test
62+
void test() {
63+
MockingDetails mockingDetails = mockingDetails(mock);
64+
MockCreationSettings<?> mockSettings = mockingDetails.getMockCreationSettings();
65+
assertThat(mockingDetails.isMock()).as("is mock").isTrue();
66+
assertThat(mockSettings.getMockName()).as("mock name").hasToString("stringService");
67+
68+
given(mock.greeting()).willReturn("mocked");
69+
assertThat(caller.sayGreeting()).isEqualTo("I say mocked 123");
70+
then(mock).should().greeting();
71+
}
72+
73+
74+
@Configuration(proxyBeanMethods = false)
75+
@Import({ ExampleGenericServiceCaller.class, IntegerExampleGenericService.class })
76+
static class Config {
77+
78+
@Bean
79+
StringExampleGenericService one() {
80+
return new StringExampleGenericService("one");
81+
}
82+
83+
@Bean
84+
// "stringService" matches the constructor argument name in ExampleGenericServiceCaller
85+
StringExampleGenericService stringService() {
86+
return new StringExampleGenericService("two");
87+
}
88+
}
89+
90+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
/*
2+
* Copyright 2012-2024 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.test.context.bean.override.mockito.integration;
18+
19+
import org.junit.jupiter.api.Disabled;
20+
import org.junit.jupiter.api.Test;
21+
import org.junit.jupiter.api.extension.ExtendWith;
22+
import org.mockito.MockingDetails;
23+
import org.mockito.mock.MockCreationSettings;
24+
25+
import org.springframework.beans.factory.annotation.Autowired;
26+
import org.springframework.context.annotation.Bean;
27+
import org.springframework.context.annotation.Configuration;
28+
import org.springframework.context.annotation.Import;
29+
import org.springframework.context.annotation.Primary;
30+
import org.springframework.test.context.bean.override.example.ExampleGenericServiceCaller;
31+
import org.springframework.test.context.bean.override.example.IntegerExampleGenericService;
32+
import org.springframework.test.context.bean.override.example.StringExampleGenericService;
33+
import org.springframework.test.context.bean.override.mockito.MockitoBean;
34+
import org.springframework.test.context.junit.jupiter.SpringExtension;
35+
36+
import static org.assertj.core.api.Assertions.assertThat;
37+
import static org.mockito.BDDMockito.given;
38+
import static org.mockito.BDDMockito.then;
39+
import static org.mockito.Mockito.mockingDetails;
40+
41+
/**
42+
* Tests that {@link MockitoBean @MockitoBean} can be used to mock a bean when
43+
* there are multiple candidates and one is primary.
44+
*
45+
* @author Sam Brannen
46+
* @author Phillip Webb
47+
* @since 6.2
48+
* @see MockitoBeanWithMultipleExistingBeansAndExplicitBeanNameIntegrationTests
49+
* @see MockitoBeanWithMultipleExistingBeansAndExplicitQualifierIntegrationTests
50+
*/
51+
@Disabled("Disabled until @Primary is supported for BeanOverrideStrategy.REPLACE_OR_CREATE")
52+
@ExtendWith(SpringExtension.class)
53+
class MockitoBeanWithMultipleExistingBeansAndOnePrimaryIntegrationTests {
54+
55+
@MockitoBean
56+
StringExampleGenericService mock;
57+
58+
@Autowired
59+
ExampleGenericServiceCaller caller;
60+
61+
62+
@Test
63+
void test() {
64+
MockingDetails mockingDetails = mockingDetails(mock);
65+
MockCreationSettings<?> mockSettings = mockingDetails.getMockCreationSettings();
66+
assertThat(mockingDetails.isMock()).as("is mock").isTrue();
67+
assertThat(mockSettings.getMockName()).as("mock name").hasToString("two");
68+
69+
given(mock.greeting()).willReturn("mocked");
70+
assertThat(caller.sayGreeting()).isEqualTo("I say mocked 123");
71+
then(mock).should().greeting();
72+
}
73+
74+
75+
@Configuration(proxyBeanMethods = false)
76+
@Import({ ExampleGenericServiceCaller.class, IntegerExampleGenericService.class })
77+
static class Config {
78+
79+
@Bean
80+
StringExampleGenericService one() {
81+
return new StringExampleGenericService("one");
82+
}
83+
84+
@Bean
85+
@Primary
86+
StringExampleGenericService two() {
87+
return new StringExampleGenericService("two");
88+
}
89+
}
90+
91+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
/*
2+
* Copyright 2012-2024 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.test.context.bean.override.mockito.integration;
18+
19+
import org.junit.jupiter.api.Test;
20+
import org.mockito.MockingDetails;
21+
import org.mockito.mock.MockCreationSettings;
22+
23+
import org.springframework.beans.factory.annotation.Autowired;
24+
import org.springframework.context.annotation.Bean;
25+
import org.springframework.context.annotation.Configuration;
26+
import org.springframework.context.annotation.Import;
27+
import org.springframework.test.context.bean.override.example.ExampleGenericServiceCaller;
28+
import org.springframework.test.context.bean.override.example.IntegerExampleGenericService;
29+
import org.springframework.test.context.bean.override.example.StringExampleGenericService;
30+
import org.springframework.test.context.bean.override.mockito.MockitoSpyBean;
31+
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
32+
33+
import static org.assertj.core.api.Assertions.assertThat;
34+
import static org.mockito.BDDMockito.then;
35+
import static org.mockito.Mockito.mockingDetails;
36+
37+
/**
38+
* Tests that {@link MockitoSpyBean @MockitoSpyBean} can be used to spy on a bean
39+
* when there are multiple candidates and an explicit bean name is supplied to
40+
* select one of the candidates.
41+
*
42+
* @author Sam Brannen
43+
* @author Phillip Webb
44+
* @since 6.2
45+
* @see MockitoSpyBeanWithMultipleExistingBeansAndExplicitQualifierIntegrationTests
46+
* @see MockitoSpyBeanWithMultipleExistingBeansAndOnePrimaryIntegrationTests
47+
*/
48+
@SpringJUnitConfig
49+
class MockitoSpyBeanWithMultipleExistingBeansAndExplicitBeanNameIntegrationTests {
50+
51+
@MockitoSpyBean("stringService")
52+
StringExampleGenericService spy;
53+
54+
@Autowired
55+
ExampleGenericServiceCaller caller;
56+
57+
58+
@Test
59+
void test() {
60+
MockingDetails mockingDetails = mockingDetails(spy);
61+
MockCreationSettings<?> mockSettings = mockingDetails.getMockCreationSettings();
62+
assertThat(mockingDetails.isSpy()).as("is spy").isTrue();
63+
assertThat(mockSettings.getMockName()).hasToString("stringService");
64+
65+
assertThat(caller.sayGreeting()).isEqualTo("I say two 123");
66+
then(spy).should().greeting();
67+
}
68+
69+
70+
@Configuration(proxyBeanMethods = false)
71+
@Import({ ExampleGenericServiceCaller.class, IntegerExampleGenericService.class })
72+
static class Config {
73+
74+
@Bean
75+
StringExampleGenericService one() {
76+
return new StringExampleGenericService("one");
77+
}
78+
79+
@Bean
80+
// "stringService" matches the constructor argument name in ExampleGenericServiceCaller
81+
StringExampleGenericService stringService() {
82+
return new StringExampleGenericService("two");
83+
}
84+
}
85+
86+
}

0 commit comments

Comments
 (0)