Skip to content

Commit 0221471

Browse files
committed
Verify @⁠Mockito[Spy]Bean can mock/spy parameterized types
See gh-33742
1 parent 3b82733 commit 0221471

6 files changed

+265
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
/*
2+
* Copyright 2002-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.example;
18+
19+
/**
20+
* Example generic service interface for tests.
21+
*
22+
* @param <T> the generic type
23+
* @author Phillip Webb
24+
* @since 6.2
25+
*/
26+
public interface ExampleGenericService<T> {
27+
28+
T greeting();
29+
30+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
/*
2+
* Copyright 2002-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.example;
18+
19+
/**
20+
* Example bean that has dependencies on parameterized {@link ExampleGenericService}
21+
* collaborators.
22+
*
23+
* @author Sam Brannen
24+
* @author Phillip Webb
25+
* @since 6.2
26+
*/
27+
public record ExampleGenericServiceCaller(ExampleGenericService<Integer> integerService,
28+
ExampleGenericService<String> stringService) {
29+
30+
public String sayGreeting() {
31+
return "I say " + this.stringService.greeting() + " " + this.integerService.greeting();
32+
}
33+
34+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
/*
2+
* Copyright 2002-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.example;
18+
19+
/**
20+
* {@link ExampleGenericService} implementation for tests.
21+
*
22+
* @author Phillip Webb
23+
* @author Sam Brannen
24+
* @since 6.2
25+
*/
26+
public class IntegerExampleGenericService implements ExampleGenericService<Integer> {
27+
28+
@Override
29+
public Integer greeting() {
30+
return 123;
31+
}
32+
33+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/*
2+
* Copyright 2002-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.example;
18+
19+
/**
20+
* {@link ExampleGenericService} implementation for tests.
21+
*
22+
* @author Sam Brannen
23+
* @author Phillip Webb
24+
* @since 6.2
25+
*/
26+
public record StringExampleGenericService(String greeting) implements ExampleGenericService<String> {
27+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
/*
2+
* Copyright 2002-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+
21+
import org.springframework.beans.factory.annotation.Autowired;
22+
import org.springframework.context.annotation.Configuration;
23+
import org.springframework.context.annotation.Import;
24+
import org.springframework.test.context.bean.override.example.ExampleGenericService;
25+
import org.springframework.test.context.bean.override.example.ExampleGenericServiceCaller;
26+
import org.springframework.test.context.bean.override.mockito.MockitoBean;
27+
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
28+
29+
import static org.assertj.core.api.Assertions.assertThat;
30+
import static org.mockito.BDDMockito.given;
31+
32+
/**
33+
* Tests that {@link MockitoBean @MockitoBean} on fields with generics can be used
34+
* to inject new mock instances.
35+
*
36+
* @author Phillip Webb
37+
* @author Sam Brannen
38+
* @since 6.2
39+
* @see MockitoSpyBeanWithGenericsOnTestFieldForExistingGenericBeanIntegrationTests
40+
*/
41+
@SpringJUnitConfig
42+
class MockitoBeanWithGenericsOnTestFieldForNewBeanIntegrationTests {
43+
44+
@MockitoBean
45+
ExampleGenericService<String> stringService;
46+
47+
@MockitoBean
48+
ExampleGenericService<Integer> integerService;
49+
50+
@Autowired
51+
ExampleGenericServiceCaller caller;
52+
53+
54+
@Test
55+
void testMocking() {
56+
given(stringService.greeting()).willReturn("Hello");
57+
given(integerService.greeting()).willReturn(42);
58+
assertThat(caller.sayGreeting()).isEqualTo("I say Hello 42");
59+
}
60+
61+
62+
@Configuration(proxyBeanMethods = false)
63+
@Import(ExampleGenericServiceCaller.class)
64+
static class Config {
65+
}
66+
67+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
/*
2+
* Copyright 2002-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+
21+
import org.springframework.beans.factory.annotation.Autowired;
22+
import org.springframework.context.annotation.Bean;
23+
import org.springframework.context.annotation.Configuration;
24+
import org.springframework.context.annotation.Import;
25+
import org.springframework.test.context.bean.override.example.ExampleGenericService;
26+
import org.springframework.test.context.bean.override.example.ExampleGenericServiceCaller;
27+
import org.springframework.test.context.bean.override.example.IntegerExampleGenericService;
28+
import org.springframework.test.context.bean.override.example.StringExampleGenericService;
29+
import org.springframework.test.context.bean.override.mockito.MockitoSpyBean;
30+
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
31+
32+
import static org.assertj.core.api.Assertions.assertThat;
33+
import static org.mockito.BDDMockito.then;
34+
35+
/**
36+
* Tests that {@link MockitoSpyBean @MockitoSpyBean} on a field with generics can
37+
* be used to replace an existing bean with matching generics.
38+
*
39+
* @author Phillip Webb
40+
* @author Sam Brannen
41+
* @since 6.2
42+
* @see MockitoBeanWithGenericsOnTestFieldForNewBeanIntegrationTests
43+
*/
44+
@SpringJUnitConfig
45+
class MockitoSpyBeanWithGenericsOnTestFieldForExistingGenericBeanIntegrationTests {
46+
47+
@MockitoSpyBean
48+
ExampleGenericService<String> service;
49+
50+
@Autowired
51+
ExampleGenericServiceCaller caller;
52+
53+
54+
@Test
55+
void testSpying() {
56+
assertThat(caller.sayGreeting()).isEqualTo("I say Enigma 123");
57+
then(service).should().greeting();
58+
}
59+
60+
61+
@Configuration(proxyBeanMethods = false)
62+
@Import({ ExampleGenericServiceCaller.class, IntegerExampleGenericService.class })
63+
static class SpyBeanOnTestFieldForExistingBeanConfig {
64+
65+
@Bean
66+
ExampleGenericService<String> simpleExampleStringGenericService() {
67+
// In order to trigger the issue, we need a method signature that returns the
68+
// generic type instead of the actual implementation class.
69+
return new StringExampleGenericService("Enigma");
70+
}
71+
72+
}
73+
74+
}

0 commit comments

Comments
 (0)