Skip to content

Commit d7829e8

Browse files
committed
test: Add unit tests for the spring-ai-mcp-annotations module
Signed-off-by: Sun Yuhan <[email protected]>
1 parent 534c6af commit d7829e8

File tree

6 files changed

+958
-1
lines changed

6 files changed

+958
-1
lines changed

mcp/mcp-annotations-spring/pom.xml

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,26 @@
4141
<version>${project.parent.version}</version>
4242
</dependency>
4343

44+
<!-- Test dependencies -->
45+
<dependency>
46+
<groupId>org.junit.jupiter</groupId>
47+
<artifactId>junit-jupiter</artifactId>
48+
<scope>test</scope>
49+
</dependency>
50+
51+
<dependency>
52+
<groupId>org.mockito</groupId>
53+
<artifactId>mockito-junit-jupiter</artifactId>
54+
<scope>test</scope>
55+
</dependency>
56+
57+
<dependency>
58+
<groupId>org.assertj</groupId>
59+
<artifactId>assertj-core</artifactId>
60+
<scope>test</scope>
61+
</dependency>
62+
4463
</dependencies>
4564

4665

47-
</project>
66+
</project>
Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
/*
2+
* Copyright 2025-2025 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.ai.mcp.annotation.spring;
18+
19+
import org.junit.jupiter.api.Test;
20+
import org.junit.jupiter.api.extension.ExtendWith;
21+
import org.mockito.MockedStatic;
22+
import org.mockito.junit.jupiter.MockitoExtension;
23+
import org.springframework.aop.framework.ProxyFactory;
24+
import org.springframework.aop.support.AopUtils;
25+
26+
import java.lang.reflect.Method;
27+
import java.util.Arrays;
28+
29+
import static org.assertj.core.api.Assertions.assertThat;
30+
import static org.mockito.Mockito.mock;
31+
import static org.mockito.Mockito.mockStatic;
32+
33+
/**
34+
* Unit Tests for {@link AnnotationProviderUtil}.
35+
*
36+
* @author Sun Yuhan
37+
*/
38+
@ExtendWith(MockitoExtension.class)
39+
class AnnotationProviderUtilTests {
40+
41+
@Test
42+
void beanMethodsWithNormalClassReturnsSortedMethods() {
43+
TestClass testBean = new TestClass();
44+
45+
Method[] methods = AnnotationProviderUtil.beanMethods(testBean);
46+
47+
assertThat(methods).isNotNull();
48+
assertThat(methods.length).isEqualTo(3);
49+
50+
assertThat(methods[0].getName()).isEqualTo("aaaMethod");
51+
assertThat(methods[1].getName()).isEqualTo("bbbMethod");
52+
assertThat(methods[2].getName()).isEqualTo("cccMethod");
53+
54+
Arrays.stream(methods).forEach(method -> assertThat(method.getDeclaringClass()).isEqualTo(TestClass.class));
55+
}
56+
57+
@Test
58+
void beanMethodsWithAopProxyReturnsTargetClassMethods() {
59+
TestClass target = new TestClass();
60+
ProxyFactory proxyFactory = new ProxyFactory(target);
61+
Object proxy = proxyFactory.getProxy();
62+
63+
Method[] methods = AnnotationProviderUtil.beanMethods(proxy);
64+
65+
assertThat(methods).isNotNull();
66+
assertThat(methods.length).isEqualTo(3);
67+
68+
Arrays.stream(methods).forEach(method -> assertThat(method.getDeclaringClass()).isEqualTo(TestClass.class));
69+
}
70+
71+
@Test
72+
void beanMethodsWithMockedAopProxyReturnsTargetClassMethods() {
73+
Object proxy = mock(Object.class);
74+
75+
try (MockedStatic<AopUtils> mockedAopUtils = mockStatic(AopUtils.class)) {
76+
mockedAopUtils.when(() -> AopUtils.isAopProxy(proxy)).thenReturn(true);
77+
mockedAopUtils.when(() -> AopUtils.getTargetClass(proxy)).thenReturn(TestClass.class);
78+
79+
Method[] methods = AnnotationProviderUtil.beanMethods(proxy);
80+
81+
assertThat(methods).isNotNull();
82+
assertThat(methods.length).isEqualTo(3);
83+
84+
mockedAopUtils.verify(() -> AopUtils.isAopProxy(proxy));
85+
mockedAopUtils.verify(() -> AopUtils.getTargetClass(proxy));
86+
}
87+
}
88+
89+
@Test
90+
void beanMethodsWithNoDeclaredMethodsReturnsEmptyArray() {
91+
NoMethodClass testBean = new NoMethodClass();
92+
93+
Method[] methods = AnnotationProviderUtil.beanMethods(testBean);
94+
95+
assertThat(methods).isNotNull();
96+
assertThat(methods).isEmpty();
97+
}
98+
99+
@Test
100+
void beanMethodsWithOverloadedMethodsReturnsCorrectlySortedMethods() {
101+
OverloadedMethodClass testBean = new OverloadedMethodClass();
102+
103+
Method[] methods = AnnotationProviderUtil.beanMethods(testBean);
104+
105+
assertThat(methods).isNotNull();
106+
assertThat(methods.length).isEqualTo(3);
107+
108+
assertThat(methods[0].getName()).isEqualTo("overloadedMethod");
109+
assertThat(methods[0].getParameterCount()).isEqualTo(0);
110+
111+
assertThat(methods[1].getName()).isEqualTo("overloadedMethod");
112+
assertThat(methods[1].getParameterCount()).isEqualTo(1);
113+
114+
assertThat(methods[2].getName()).isEqualTo("simpleMethod");
115+
}
116+
117+
static class TestClass {
118+
119+
public void cccMethod() {
120+
}
121+
122+
public void aaaMethod() {
123+
}
124+
125+
public void bbbMethod() {
126+
}
127+
128+
}
129+
130+
static class NoMethodClass {
131+
132+
}
133+
134+
static class OverloadedMethodClass {
135+
136+
public void simpleMethod() {
137+
}
138+
139+
public void overloadedMethod(String param) {
140+
}
141+
142+
public void overloadedMethod() {
143+
}
144+
145+
}
146+
147+
}
Lines changed: 219 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,219 @@
1+
/*
2+
* Copyright 2025-2025 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.ai.mcp.annotation.spring;
18+
19+
import io.modelcontextprotocol.server.McpServerFeatures;
20+
import io.modelcontextprotocol.server.McpStatelessServerFeatures;
21+
import org.junit.jupiter.api.Test;
22+
import org.junit.jupiter.api.extension.ExtendWith;
23+
import org.mockito.junit.jupiter.MockitoExtension;
24+
import org.springaicommunity.mcp.method.changed.prompt.AsyncPromptListChangedSpecification;
25+
import org.springaicommunity.mcp.method.changed.resource.AsyncResourceListChangedSpecification;
26+
import org.springaicommunity.mcp.method.changed.tool.AsyncToolListChangedSpecification;
27+
import org.springaicommunity.mcp.method.elicitation.AsyncElicitationSpecification;
28+
import org.springaicommunity.mcp.method.logging.AsyncLoggingSpecification;
29+
import org.springaicommunity.mcp.method.progress.AsyncProgressSpecification;
30+
import org.springaicommunity.mcp.method.sampling.AsyncSamplingSpecification;
31+
32+
import java.util.ArrayList;
33+
import java.util.List;
34+
35+
import static org.junit.jupiter.api.Assertions.assertNotNull;
36+
import static org.junit.jupiter.api.Assertions.assertTrue;
37+
38+
/**
39+
* Unit Tests for {@link AsyncMcpAnnotationProviders}.
40+
*
41+
* @author Sun Yuhan
42+
*/
43+
@ExtendWith(MockitoExtension.class)
44+
class AsyncMcpAnnotationProvidersTests {
45+
46+
@Test
47+
void testLoggingSpecifications() {
48+
List<Object> loggingObjects = new ArrayList<>();
49+
loggingObjects.add(new Object());
50+
51+
List<AsyncLoggingSpecification> result = AsyncMcpAnnotationProviders.loggingSpecifications(loggingObjects);
52+
53+
assertNotNull(result);
54+
}
55+
56+
@Test
57+
void testLoggingSpecificationsWithEmptyList() {
58+
List<Object> loggingObjects = new ArrayList<>();
59+
60+
List<AsyncLoggingSpecification> result = AsyncMcpAnnotationProviders.loggingSpecifications(loggingObjects);
61+
62+
assertNotNull(result);
63+
assertTrue(result.isEmpty());
64+
}
65+
66+
@Test
67+
void testSamplingSpecifications() {
68+
List<Object> samplingObjects = new ArrayList<>();
69+
samplingObjects.add(new Object());
70+
71+
List<AsyncSamplingSpecification> result = AsyncMcpAnnotationProviders.samplingSpecifications(samplingObjects);
72+
73+
assertNotNull(result);
74+
}
75+
76+
@Test
77+
void testElicitationSpecifications() {
78+
List<Object> elicitationObjects = new ArrayList<>();
79+
elicitationObjects.add(new Object());
80+
81+
List<AsyncElicitationSpecification> result = AsyncMcpAnnotationProviders
82+
.elicitationSpecifications(elicitationObjects);
83+
84+
assertNotNull(result);
85+
}
86+
87+
@Test
88+
void testProgressSpecifications() {
89+
List<Object> progressObjects = new ArrayList<>();
90+
progressObjects.add(new Object());
91+
92+
List<AsyncProgressSpecification> result = AsyncMcpAnnotationProviders.progressSpecifications(progressObjects);
93+
94+
assertNotNull(result);
95+
}
96+
97+
@Test
98+
void testToolSpecifications() {
99+
List<Object> toolObjects = new ArrayList<>();
100+
toolObjects.add(new Object());
101+
102+
List<McpServerFeatures.AsyncToolSpecification> result = AsyncMcpAnnotationProviders
103+
.toolSpecifications(toolObjects);
104+
105+
assertNotNull(result);
106+
}
107+
108+
@Test
109+
void testStatelessToolSpecifications() {
110+
111+
List<Object> toolObjects = new ArrayList<>();
112+
toolObjects.add(new Object());
113+
114+
List<McpStatelessServerFeatures.AsyncToolSpecification> result = AsyncMcpAnnotationProviders
115+
.statelessToolSpecifications(toolObjects);
116+
117+
assertNotNull(result);
118+
}
119+
120+
@Test
121+
void testCompleteSpecifications() {
122+
List<Object> completeObjects = new ArrayList<>();
123+
completeObjects.add(new Object());
124+
125+
List<McpServerFeatures.AsyncCompletionSpecification> result = AsyncMcpAnnotationProviders
126+
.completeSpecifications(completeObjects);
127+
128+
assertNotNull(result);
129+
}
130+
131+
@Test
132+
void testStatelessCompleteSpecifications() {
133+
List<Object> completeObjects = new ArrayList<>();
134+
completeObjects.add(new Object());
135+
136+
List<McpStatelessServerFeatures.AsyncCompletionSpecification> result = AsyncMcpAnnotationProviders
137+
.statelessCompleteSpecifications(completeObjects);
138+
139+
assertNotNull(result);
140+
}
141+
142+
@Test
143+
void testPromptSpecifications() {
144+
List<Object> promptObjects = new ArrayList<>();
145+
promptObjects.add(new Object());
146+
147+
List<McpServerFeatures.AsyncPromptSpecification> result = AsyncMcpAnnotationProviders
148+
.promptSpecifications(promptObjects);
149+
150+
assertNotNull(result);
151+
}
152+
153+
@Test
154+
void testStatelessPromptSpecifications() {
155+
List<Object> promptObjects = new ArrayList<>();
156+
promptObjects.add(new Object());
157+
158+
List<McpStatelessServerFeatures.AsyncPromptSpecification> result = AsyncMcpAnnotationProviders
159+
.statelessPromptSpecifications(promptObjects);
160+
161+
assertNotNull(result);
162+
}
163+
164+
@Test
165+
void testResourceSpecifications() {
166+
List<Object> resourceObjects = new ArrayList<>();
167+
resourceObjects.add(new Object());
168+
169+
List<McpServerFeatures.AsyncResourceSpecification> result = AsyncMcpAnnotationProviders
170+
.resourceSpecifications(resourceObjects);
171+
172+
assertNotNull(result);
173+
}
174+
175+
@Test
176+
void testStatelessResourceSpecifications() {
177+
List<Object> resourceObjects = new ArrayList<>();
178+
resourceObjects.add(new Object());
179+
180+
List<McpStatelessServerFeatures.AsyncResourceSpecification> result = AsyncMcpAnnotationProviders
181+
.statelessResourceSpecifications(resourceObjects);
182+
183+
assertNotNull(result);
184+
}
185+
186+
@Test
187+
void testResourceListChangedSpecifications() {
188+
List<Object> resourceListChangedObjects = new ArrayList<>();
189+
resourceListChangedObjects.add(new Object());
190+
191+
List<AsyncResourceListChangedSpecification> result = AsyncMcpAnnotationProviders
192+
.resourceListChangedSpecifications(resourceListChangedObjects);
193+
194+
assertNotNull(result);
195+
}
196+
197+
@Test
198+
void testToolListChangedSpecifications() {
199+
List<Object> toolListChangedObjects = new ArrayList<>();
200+
toolListChangedObjects.add(new Object());
201+
202+
List<AsyncToolListChangedSpecification> result = AsyncMcpAnnotationProviders
203+
.toolListChangedSpecifications(toolListChangedObjects);
204+
205+
assertNotNull(result);
206+
}
207+
208+
@Test
209+
void testPromptListChangedSpecifications() {
210+
List<Object> promptListChangedObjects = new ArrayList<>();
211+
promptListChangedObjects.add(new Object());
212+
213+
List<AsyncPromptListChangedSpecification> result = AsyncMcpAnnotationProviders
214+
.promptListChangedSpecifications(promptListChangedObjects);
215+
216+
assertNotNull(result);
217+
}
218+
219+
}

0 commit comments

Comments
 (0)