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

使用Mockito-Kotlin为Corda单元测试模拟链外服务遇阻求助

我来帮你搞定这个问题!你遇到的核心问题是模拟对象没被正确注入到Corda节点的依赖体系里,导致节点还是在调用真实的ExternalService实例。下面是一步步的解决方法和完整示例:

解决方法与实现示例

1. 先修正Mockito-Kotlin的模拟语法

你当前的模拟写法存在语法错误,这会导致模拟逻辑根本没生效。推荐用Mockito-Kotlin的扩展函数,写法更简洁直观:

// 确保已添加Mockito-Kotlin依赖(测试环境)
testImplementation "com.nhaarman.mockitokotlin2:mockito-kotlin:2.2.0"

// 正确的模拟写法
val mockExternalService = mock<ExternalService>()
whenever(mockExternalService.callExternalService()).thenReturn("Hello")

如果用原生Mockito的话,正确写法是:

val mockExternalService = Mockito.mock(ExternalService::class.java)
Mockito.`when`(mockExternalService.callExternalService()).thenReturn("Hello")

你之前的代码多了多余的.toString(),而且doReturn的调用方式也不对,这直接导致模拟规则没被正确设置。

2. 将模拟服务注入到Corda测试节点

Corda节点启动时会通过依赖注入框架实例化服务类,所以我们需要在测试中自定义节点配置,把真实的ExternalService替换成模拟对象。

完整单元测试示例

假设你的ExternalService是作为Corda服务被节点使用的,下面是完整的测试代码:

import net.corda.testing.node.MockNetwork
import net.corda.testing.node.MockNetworkParameters
import net.corda.testing.node.StartedMockNode
import org.junit.After
import org.junit.Before
import org.junit.Test
import com.nhaarman.mockitokotlin2.mock
import com.nhaarman.mockitokotlin2.whenever
import org.junit.Assert.assertEquals

class ExternalServiceIntegrationTest {
    private lateinit var mockNetwork: MockNetwork
    private lateinit var testNode: StartedMockNode
    private lateinit var mockExternalService: ExternalService

    @Before
    fun setupTestEnvironment() {
        // 1. 创建并配置模拟服务
        mockExternalService = mock()
        whenever(mockExternalService.callExternalService()).thenReturn("Hello")

        // 2. 初始化MockNetwork,并将模拟服务注入节点
        mockNetwork = MockNetwork(MockNetworkParameters(
            cordappsForAllNodes = listOf(
                // 加载你的业务Cordapp(如果需要的话)
            )
        ))

        testNode = mockNetwork.createMockNode().apply {
            // 注册模拟服务,覆盖节点默认的真实服务实例
            services.registerService(ExternalService::class.java, mockExternalService)
        }
    }

    @Test
    fun `verify mocked external service returns expected value`() {
        // 3. 从节点服务中心获取模拟服务(和流中获取方式一致)
        val serviceFromNode = testNode.services.cordaService(ExternalService::class.java)
        val result = serviceFromNode.callExternalService()

        // 验证结果符合预期
        assertEquals("Hello", result)
    }

    @Test
    fun `test flow uses mocked external service`() {
        // 启动你的业务流,流中通过serviceHub获取ExternalService时,会拿到模拟实例
        val flow = YourBusinessFlow()
        val future = testNode.startFlow(flow)
        mockNetwork.runNetwork()

        // 验证流的输出是否依赖模拟服务的返回值
        val flowResult = future.get()
        // 这里根据你的流逻辑添加断言,比如:
        // assertEquals("Processed: Hello", flowResult)
    }

    @After
    fun tearDown() {
        mockNetwork.stopNodes()
    }
}

3. 关键注意事项

  • 确保你的业务流中是通过serviceHub.cordaService(ExternalService::class.java)获取服务实例,而不是直接new ExternalService(),这样才能拿到注入的模拟对象。
  • 如果你的ExternalService带有@CordaService注解,节点启动时会自动创建真实实例,这时候必须用services.registerService覆盖默认实例,才能让节点使用模拟对象。
  • 所有流的测试必须运行在MockNetwork的上下文里,确保流能访问到节点注入的模拟服务。

这样修改后,你的单元测试就会完全依赖模拟的ExternalService,不再调用真实的外部系统了。

内容的提问来源于stack exchange,提问作者Rickky13

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 03:51:11