Skip to content

Commit 8cf2ea5

Browse files
sunyuhan1998SenreySong
authored andcommitted
test: Add unit tests for the spring-ai-mcp-annotations module
Signed-off-by: Sun Yuhan <[email protected]>
1 parent 3cb08d7 commit 8cf2ea5

File tree

6 files changed

+970
-1
lines changed

6 files changed

+970
-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: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
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 java.lang.reflect.Method;
20+
import java.util.Arrays;
21+
22+
import org.junit.jupiter.api.Test;
23+
import org.junit.jupiter.api.extension.ExtendWith;
24+
import org.mockito.MockedStatic;
25+
import org.mockito.junit.jupiter.MockitoExtension;
26+
27+
import org.springframework.aop.framework.ProxyFactory;
28+
import org.springframework.aop.support.AopUtils;
29+
30+
import static org.assertj.core.api.Assertions.assertThat;
31+
import static org.mockito.Mockito.mock;
32+
import static org.mockito.Mockito.mockStatic;
33+
34+
/**
35+
* Unit Tests for {@link AnnotationProviderUtil}.
36+
*
37+
* @author Sun Yuhan
38+
*/
39+
@ExtendWith(MockitoExtension.class)
40+
class AnnotationProviderUtilTests {
41+
42+
@Test
43+
void beanMethodsWithNormalClassReturnsSortedMethods() {
44+
TestClass testBean = new TestClass();
45+
46+
Method[] methods = AnnotationProviderUtil.beanMethods(testBean);
47+
48+
assertThat(methods).isNotNull();
49+
assertThat(methods.length).isEqualTo(3);
50+
51+
assertThat(methods[0].getName()).isEqualTo("aaaMethod");
52+
assertThat(methods[1].getName()).isEqualTo("bbbMethod");
53+
assertThat(methods[2].getName()).isEqualTo("cccMethod");
54+
55+
Arrays.stream(methods).forEach(method -> assertThat(method.getDeclaringClass()).isEqualTo(TestClass.class));
56+
}
57+
58+
@Test
59+
void beanMethodsWithAopProxyReturnsTargetClassMethods() {
60+
TestClass target = new TestClass();
61+
ProxyFactory proxyFactory = new ProxyFactory(target);
62+
Object proxy = proxyFactory.getProxy();
63+
64+
Method[] methods = AnnotationProviderUtil.beanMethods(proxy);
65+
66+
assertThat(methods).isNotNull();
67+
assertThat(methods.length).isEqualTo(3);
68+
69+
Arrays.stream(methods).forEach(method -> assertThat(method.getDeclaringClass()).isEqualTo(TestClass.class));
70+
}
71+
72+
@Test
73+
void beanMethodsWithMockedAopProxyReturnsTargetClassMethods() {
74+
Object proxy = mock(Object.class);
75+
76+
try (MockedStatic<AopUtils> mockedAopUtils = mockStatic(AopUtils.class)) {
77+
mockedAopUtils.when(() -> AopUtils.isAopProxy(proxy)).thenReturn(true);
78+
mockedAopUtils.when(() -> AopUtils.getTargetClass(proxy)).thenReturn(TestClass.class);
79+
80+
Method[] methods = AnnotationProviderUtil.beanMethods(proxy);
81+
82+
assertThat(methods).isNotNull();
83+
assertThat(methods.length).isEqualTo(3);
84+
85+
mockedAopUtils.verify(() -> AopUtils.isAopProxy(proxy));
86+
mockedAopUtils.verify(() -> AopUtils.getTargetClass(proxy));
87+
}
88+
}
89+
90+
@Test
91+
void beanMethodsWithNoDeclaredMethodsReturnsEmptyArray() {
92+
NoMethodClass testBean = new NoMethodClass();
93+
94+
Method[] methods = AnnotationProviderUtil.beanMethods(testBean);
95+
96+
assertThat(methods).isNotNull();
97+
assertThat(methods).isEmpty();
98+
}
99+
100+
@Test
101+
void beanMethodsWithOverloadedMethodsReturnsCorrectlySortedMethods() {
102+
OverloadedMethodClass testBean = new OverloadedMethodClass();
103+
104+
Method[] methods = AnnotationProviderUtil.beanMethods(testBean);
105+
106+
assertThat(methods).isNotNull();
107+
assertThat(methods.length).isEqualTo(3);
108+
109+
assertThat(methods[0].getName()).isEqualTo("overloadedMethod");
110+
assertThat(methods[0].getParameterCount()).isEqualTo(0);
111+
112+
assertThat(methods[1].getName()).isEqualTo("overloadedMethod");
113+
assertThat(methods[1].getParameterCount()).isEqualTo(1);
114+
115+
assertThat(methods[2].getName()).isEqualTo("simpleMethod");
116+
}
117+
118+
static class TestClass {
119+
120+
public void cccMethod() {
121+
}
122+
123+
public void aaaMethod() {
124+
}
125+
126+
public void bbbMethod() {
127+
}
128+
129+
}
130+
131+
static class NoMethodClass {
132+
133+
}
134+
135+
static class OverloadedMethodClass {
136+
137+
public void simpleMethod() {
138+
}
139+
140+
public void overloadedMethod(String param) {
141+
}
142+
143+
public void overloadedMethod() {
144+
}
145+
146+
}
147+
148+
}
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 java.util.ArrayList;
20+
import java.util.List;
21+
22+
import io.modelcontextprotocol.server.McpServerFeatures;
23+
import io.modelcontextprotocol.server.McpStatelessServerFeatures;
24+
import org.junit.jupiter.api.Test;
25+
import org.junit.jupiter.api.extension.ExtendWith;
26+
import org.mockito.junit.jupiter.MockitoExtension;
27+
import org.springaicommunity.mcp.method.changed.prompt.AsyncPromptListChangedSpecification;
28+
import org.springaicommunity.mcp.method.changed.resource.AsyncResourceListChangedSpecification;
29+
import org.springaicommunity.mcp.method.changed.tool.AsyncToolListChangedSpecification;
30+
import org.springaicommunity.mcp.method.elicitation.AsyncElicitationSpecification;
31+
import org.springaicommunity.mcp.method.logging.AsyncLoggingSpecification;
32+
import org.springaicommunity.mcp.method.progress.AsyncProgressSpecification;
33+
import org.springaicommunity.mcp.method.sampling.AsyncSamplingSpecification;
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)