Skip to content

Commit 0b5a6bb

Browse files
committed
feat(test): Add unit tests for MCP component scanning
1 parent d556540 commit 0b5a6bb

File tree

8 files changed

+165
-10
lines changed

8 files changed

+165
-10
lines changed

pom.xml

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,13 +44,16 @@
4444
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
4545
<!--==================== maven plugin versions ====================-->
4646
<central-publishing-maven-plugin.version>0.7.0</central-publishing-maven-plugin.version>
47+
<jacoco-maven-plugin.version>0.8.12</jacoco-maven-plugin.version>
4748
<maven-gpg-plugin.version>3.1.0</maven-gpg-plugin.version>
4849
<maven-javadoc-plugin.version>3.6.3</maven-javadoc-plugin.version>
4950
<maven-source-plugin.version>3.3.0</maven-source-plugin.version>
51+
<maven-surefire-plugin.version>3.2.3</maven-surefire-plugin.version>
5052
<sortpom-maven-plugin.version>4.0.0</sortpom-maven-plugin.version>
5153
<!--==================== dependency versions ======================-->
52-
<mcp-sdk.version>0.9.0-SNAPSHOT</mcp-sdk.version>
5354
<jetty.version>12.0.18</jetty.version>
55+
<junit5.version>5.10.2</junit5.version>
56+
<mcp-sdk.version>0.9.0-SNAPSHOT</mcp-sdk.version>
5457
<reflections.version>0.10.2</reflections.version>
5558
</properties>
5659

@@ -77,6 +80,12 @@
7780
<artifactId>jetty-ee10-servlet</artifactId>
7881
<version>${jetty.version}</version>
7982
</dependency>
83+
<dependency>
84+
<groupId>org.junit.jupiter</groupId>
85+
<artifactId>junit-jupiter</artifactId>
86+
<version>${junit5.version}</version>
87+
<scope>test</scope>
88+
</dependency>
8089
<dependency>
8190
<groupId>org.reflections</groupId>
8291
<artifactId>reflections</artifactId>
@@ -147,6 +156,41 @@
147156
</execution>
148157
</executions>
149158
</plugin>
159+
<plugin>
160+
<groupId>org.apache.maven.plugins</groupId>
161+
<artifactId>maven-surefire-plugin</artifactId>
162+
<version>${maven-surefire-plugin.version}</version>
163+
<configuration>
164+
<!--suppress UnresolvedMavenProperty for IntelliJ IDEA-->
165+
<argLine>${jacoco.agent.argLine}</argLine>
166+
</configuration>
167+
</plugin>
168+
<plugin>
169+
<groupId>org.jacoco</groupId>
170+
<artifactId>jacoco-maven-plugin</artifactId>
171+
<version>${jacoco-maven-plugin.version}</version>
172+
<executions>
173+
<execution>
174+
<id>pre-unit-test</id>
175+
<goals>
176+
<goal>prepare-agent</goal>
177+
</goals>
178+
<configuration>
179+
<propertyName>jacoco.agent.argLine</propertyName>
180+
</configuration>
181+
</execution>
182+
<execution>
183+
<id>post-unit-test</id>
184+
<goals>
185+
<goal>report</goal>
186+
</goals>
187+
<phase>test</phase>
188+
<configuration>
189+
<outputDirectory>${project.build.directory}/unit-test-report</outputDirectory>
190+
</configuration>
191+
</execution>
192+
</executions>
193+
</plugin>
150194
<plugin>
151195
<groupId>org.sonatype.central</groupId>
152196
<artifactId>central-publishing-maven-plugin</artifactId>

src/main/java/com/github/codeboyzhou/mcp/declarative/McpServers.java

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,12 @@
11
package com.github.codeboyzhou.mcp.declarative;
22

33
import com.fasterxml.jackson.databind.ObjectMapper;
4-
import com.github.codeboyzhou.mcp.declarative.annotation.*;
4+
import com.github.codeboyzhou.mcp.declarative.annotation.McpComponentScan;
5+
import com.github.codeboyzhou.mcp.declarative.annotation.McpResource;
6+
import com.github.codeboyzhou.mcp.declarative.annotation.McpResources;
7+
import com.github.codeboyzhou.mcp.declarative.annotation.McpTool;
8+
import com.github.codeboyzhou.mcp.declarative.annotation.McpToolParam;
9+
import com.github.codeboyzhou.mcp.declarative.annotation.McpTools;
510
import com.github.codeboyzhou.mcp.declarative.util.ReflectionHelper;
611
import io.modelcontextprotocol.server.McpServer;
712
import io.modelcontextprotocol.server.McpServerFeatures;
@@ -18,7 +23,11 @@
1823

1924
import java.lang.reflect.Method;
2025
import java.lang.reflect.Parameter;
21-
import java.util.*;
26+
import java.util.ArrayList;
27+
import java.util.HashMap;
28+
import java.util.List;
29+
import java.util.Map;
30+
import java.util.Set;
2231

2332
public class McpServers {
2433

@@ -47,16 +56,22 @@ public class McpServers {
4756

4857
public static McpServers run(Class<?> applicationMainClass, String[] args) {
4958
McpComponentScan scan = applicationMainClass.getAnnotation(McpComponentScan.class);
50-
if (scan == null) {
51-
reflections = new Reflections(applicationMainClass.getPackageName());
52-
} else if (!scan.basePackage().trim().isBlank()) {
53-
reflections = new Reflections(scan.basePackage());
54-
} else if (scan.basePackageClass() != Object.class) {
55-
reflections = new Reflections(scan.basePackageClass().getPackageName());
56-
}
59+
reflections = new Reflections(determineBasePackage(scan, applicationMainClass));
5760
return INSTANCE;
5861
}
5962

63+
private static String determineBasePackage(McpComponentScan scan, Class<?> applicationMainClass) {
64+
if (scan != null) {
65+
if (!scan.basePackage().trim().isBlank()) {
66+
return scan.basePackage();
67+
}
68+
if (scan.basePackageClass() != Object.class) {
69+
return scan.basePackageClass().getPackageName();
70+
}
71+
}
72+
return applicationMainClass.getPackageName();
73+
}
74+
6075
public void startSyncStdioServer(String name, String version) {
6176
McpSyncServer server = McpServer.sync(new StdioServerTransportProvider())
6277
.capabilities(DEFAULT_SERVER_CAPABILITIES)
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
package com.github.codeboyzhou.mcp.declarative;
2+
3+
import com.github.codeboyzhou.mcp.declarative.annotation.McpTools;
4+
import com.github.codeboyzhou.mcp.declarative.server.TestMcpTools;
5+
import com.github.codeboyzhou.mcp.declarative.server.TestMcpComponentScanBasePackageClass;
6+
import com.github.codeboyzhou.mcp.declarative.server.TestMcpComponentScanBasePackageString;
7+
import com.github.codeboyzhou.mcp.declarative.server.TestMcpComponentScanDefault;
8+
import com.github.codeboyzhou.mcp.declarative.server.TestMcpComponentScanIsNull;
9+
import org.junit.jupiter.api.AfterEach;
10+
import org.junit.jupiter.api.BeforeEach;
11+
import org.junit.jupiter.params.ParameterizedTest;
12+
import org.junit.jupiter.params.provider.ValueSource;
13+
import org.reflections.Reflections;
14+
import org.reflections.scanners.Scanners;
15+
16+
import java.lang.reflect.Field;
17+
import java.util.Map;
18+
import java.util.Set;
19+
20+
import static org.junit.jupiter.api.Assertions.assertEquals;
21+
import static org.junit.jupiter.api.Assertions.assertNotNull;
22+
23+
class McpServersTest {
24+
25+
static final String[] EMPTY_ARGS = new String[]{};
26+
27+
Reflections reflections;
28+
29+
@BeforeEach
30+
void setUp() {
31+
reflections = null;
32+
}
33+
34+
@AfterEach
35+
void tearDown() throws NoSuchFieldException, IllegalAccessException {
36+
reflections = getReflectionsField();
37+
assertNotNull(reflections);
38+
Map<String, Set<String>> scannedClasses = reflections.getStore().get(Scanners.TypesAnnotated.name());
39+
Set<String> scannedToolClass = scannedClasses.get(McpTools.class.getName());
40+
assertEquals(1, scannedToolClass.size());
41+
assertEquals(scannedToolClass.iterator().next(), TestMcpTools.class.getName());
42+
}
43+
44+
@ParameterizedTest
45+
@ValueSource(classes = {
46+
TestMcpComponentScanIsNull.class,
47+
TestMcpComponentScanBasePackageString.class,
48+
TestMcpComponentScanBasePackageClass.class,
49+
TestMcpComponentScanDefault.class
50+
})
51+
void testRun(Class<?> applicationMainClass) {
52+
McpServers.run(applicationMainClass, EMPTY_ARGS);
53+
}
54+
55+
private Reflections getReflectionsField() throws NoSuchFieldException, IllegalAccessException {
56+
Field reflectionsField = McpServers.class.getDeclaredField("reflections");
57+
reflectionsField.setAccessible(true);
58+
Reflections reflections = (Reflections) reflectionsField.get(null);
59+
reflectionsField.setAccessible(false);
60+
return reflections;
61+
}
62+
63+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package com.github.codeboyzhou.mcp.declarative.server;
2+
3+
import com.github.codeboyzhou.mcp.declarative.annotation.McpComponentScan;
4+
5+
@McpComponentScan(basePackageClass = TestMcpComponentScanBasePackageClass.class)
6+
public class TestMcpComponentScanBasePackageClass {
7+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package com.github.codeboyzhou.mcp.declarative.server;
2+
3+
import com.github.codeboyzhou.mcp.declarative.annotation.McpComponentScan;
4+
5+
@McpComponentScan(basePackage = "com.github.codeboyzhou.mcp.declarative.server")
6+
public class TestMcpComponentScanBasePackageString {
7+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package com.github.codeboyzhou.mcp.declarative.server;
2+
3+
import com.github.codeboyzhou.mcp.declarative.annotation.McpComponentScan;
4+
5+
@McpComponentScan
6+
public class TestMcpComponentScanDefault {
7+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
package com.github.codeboyzhou.mcp.declarative.server;
2+
3+
public class TestMcpComponentScanIsNull {
4+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package com.github.codeboyzhou.mcp.declarative.server;
2+
3+
import com.github.codeboyzhou.mcp.declarative.annotation.McpTools;
4+
5+
@McpTools
6+
public class TestMcpTools {
7+
8+
}

0 commit comments

Comments
 (0)