使用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
相关产品推荐
相关产品推荐

