You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

微服务架构下结合真实数据库与真实HTTP调用的测试方案及跨服务调用连接拒绝问题排查

微服务架构下结合真实数据库与真实HTTP调用的测试方案及跨服务调用连接拒绝问题排查

看起来你在微服务集成测试里踩了几个典型的小坑——跨服务调用时的连接拒绝,还有对Mock工具的误用,我之前做微服务测试的时候也碰到过几乎一样的问题,来给你一步步理清楚怎么解决:

先拆解你当前代码里的核心问题

  1. Mock对象导致真实调用失效:你用了@Mock private ApiClient apiClient,这个Mock对象是个“假的”客户端,它不会真的发送HTTP请求到用户服务,所以当authService.createInvitationForUserToJoin执行时,本质上是在调用一个空实现;如果你的ApiClient配置里硬编码了localhost:8080,又没有真实服务在这个端口启动,自然就会报连接拒绝。
  2. MockMvc的误用:你在测试里用mockMvc.perform(get("/users/{id}", id)),但MockMvc是绑定到当前认证服务的Spring MVC上下文的,/users/{id}是用户服务的接口,认证服务里根本没有这个控制器,所以这个测试步骤本身就会返回404,完全起不到验证用户服务接口的作用。
  3. 未启动真实HTTP服务器:默认的@SpringBootTest不会启动真实的内嵌服务器(除非指定webEnvironment),所以即使你有真实的ApiClient,也没有可访问的HTTP端口来处理请求。

解决方案:构建真实数据库+真实跨服务调用的集成测试

你的Testcontainers配置其实已经搞定了真实数据库的部分,现在只需要补充“启动真实服务”和“正确配置跨服务调用”的环节:

步骤1:让测试启动真实的内嵌服务器

修改@SpringBootTest注解,指定随机端口启动真实的Web服务,避免本地端口冲突:

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)

步骤2:用Testcontainers启动用户服务实例

如果你的用户服务已经打包成Docker镜像,直接用GenericContainer启动它,并且让它连接到同一个Testcontainers管理的PostgreSQL:

@Container
static GenericContainer<?> userServiceContainer = new GenericContainer<>("your-user-service-image:latest")
    .withExposedPorts(8080)
    // 配置用户服务连接测试数据库
    .withEnv("SPRING_DATASOURCE_URL", 
        "jdbc:postgresql://" + postgreSQLContainer.getHost() + ":" + postgreSQLContainer.getMappedPort(5432) + "/testdb")
    .withEnv("SPRING_DATASOURCE_USERNAME", "postgres")
    .withEnv("SPRING_DATASOURCE_PASSWORD", "testpass");

如果是多模块项目不想打包Docker,也可以在测试类中直接引入用户服务的Spring上下文(启动速度会慢一些,但适合本地开发):

@SpringBootTest(classes = {AuthServiceApplication.class, UserServiceApplication.class})

步骤3:配置真实的ApiClient,指向用户服务地址

去掉@Mock private ApiClient apiClient,改用@Autowired注入真实的客户端实例,然后在测试初始化时配置用户服务的真实地址:

@Autowired
private ApiClient apiClient;

@BeforeEach
void setUp() {
    // 获取用户服务容器的真实地址(IP+端口)
    String userServiceBaseUrl = "http://" + userServiceContainer.getHost() + ":" + userServiceContainer.getMappedPort(8080);
    apiClient.setBasePath(userServiceBaseUrl);
}

步骤4:调整测试逻辑,用真实HTTP客户端验证接口

放弃用MockMvc调用其他服务的接口,改用TestRestTemplate或WebClient调用用户服务的真实HTTP接口:

@Autowired
private TestRestTemplate testRestTemplate;

@Test
void testCreateInvitation() throws Exception {
    // 1. 调用用户服务的创建用户接口
    AdminUser dummyAdmin = TestUtils.dummyAdminUser();
    CreateUserRequestDTO createUserRequest = DTOConverter.toCreateUserRequestDTO(dummyAdmin);
    User createdUser = testRestTemplate.postForObject("/users", createUserRequest, User.class);
    assertNotNull(createdUser);

    // 2. 验证用户服务的查询接口可正常访问
    User fetchedUser = testRestTemplate.getForObject("/users/{id}", User.class, createdUser.getId());
    assertEquals(createdUser.getId(), fetchedUser.getId());

    // 3. 调用认证服务的邀请创建方法,触发跨服务调用
    authService.createInvitationForUserToJoin(createdUser.getId());
    
    // 这里可以添加断言,比如检查数据库中是否生成了对应的邀请记录
    // Invitation invitation = invitationService.findByUserId(createdUser.getId());
    // assertNotNull(invitation);
}

额外的连接拒绝排查技巧

如果还是报连接拒绝,你可以从这几个方向查:

  1. 检查用户服务容器是否真的启动成功:在测试里打印userServiceContainer.isRunning(),或者查看Testcontainers的日志输出。
  2. 验证容器网络连通性:Testcontainers默认会给所有容器分配同一个网络,所以用容器IP调用没问题,不要硬编码localhost,因为容器里的localhost和本地主机的localhost不是同一个环境。
  3. 检查用户服务的配置:确保用户服务的端口是8080,或者在withExposedPorts里指定正确的暴露端口。
  4. 关闭本地防火墙:有时候本地防火墙会阻止容器之间的连接请求。

内容来源于stack exchange

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.08 11:14:52