Spring boot Spring启动测试:无法绑定@ConfigurationProperties-确保未应用@ConstructorBinding

Spring boot Spring启动测试:无法绑定@ConfigurationProperties-确保未应用@ConstructorBinding,spring-boot,unit-testing,kotlin,mockito,junit5,Spring Boot,Unit Testing,Kotlin,Mockito,Junit5,在Spring引导单元测试中,如何模拟@ConstructorBinding@ConfigurationProperties数据类 安装程序 两者 Kotlin 1.4.30(用于单元测试和配置类) Java15(带--启用预览)(用于业务逻辑) 弹簧靴2.4.2 Junit 5.7.1 Mockito(Mockito内联)3.7.7 Maven 3.6.3_1 我想用不同的配置测试FtpService(一个@Service,它有一个RestTemplate) FtpService的属

在Spring引导单元测试中,如何模拟@ConstructorBinding@ConfigurationProperties数据类

安装程序
  • 两者
    • Kotlin 1.4.30(用于单元测试和配置类)
    • Java15(带--启用预览)(用于业务逻辑)
  • 弹簧靴2.4.2
  • Junit 5.7.1
  • Mockito(Mockito内联)3.7.7
  • Maven 3.6.3_1
我想用不同的配置测试FtpService(一个
@Service
,它有一个
RestTemplate

FtpService的属性来自Kotlin数据类UrlProperties,它用
ConstructorBinding
@ConfigurationProperties
注释

注意:FtpService的构造函数从UrlProperties提取属性。这意味着在弹簧加载FtpService之前,UrlProperties必须同时模拟存根

错误 当我尝试模拟UrlProperties以便为不同的测试设置属性时,我要么收到错误,要么无法插入bean

Cannot bind @ConfigurationProperties for bean 'urlProperties'. Ensure that @ConstructorBinding has not been applied to regular bean

代码 `@FtpService的SpringBootTest`src/test/kotlin/com/example/FtpServiceTest.kt`
import com.example.service.FtpService
导入com.example.service.UrlProperties
导入org.junit.jupiter.api.Assertions.assertEquals
导入org.junit.jupiter.api.Test
导入org.mockito.mockito.`何时`
导入org.mockito.mockito.mock
导入org.springframework.beans.factory.annotation.Autowired
导入org.springframework.boot.test.autoconfigure.web.client.AutoConfigureWebClient
导入org.springframework.boot.test.context.SpringBootTest
导入org.springframework.boot.test.context.TestConfiguration
导入org.springframework.boot.test.mock.mockito.MockBean
导入org.springframework.context.annotation.Bean
导入org.springframework.test.context.ContextConfiguration
@测试配置
@SpringBootTest(类=[FtpService::类])
@AutoConfigureWebClient(registerRestTemplate=true)
类FTP服务测试
@自动连线构造器(
专用val ftpService:ftpService
) {
//MockBean插入Spring上下文太晚了,
//FtpService构造函数抛出NPE
//@MockBean
//lateinit var urlProperties:urlProperties
@上下文配置
类MyTestContext{
//错误-
//>无法为bean“urlProperties”绑定@ConfigurationProperties。
//>确保@ConstructorBinding未应用于常规bean
var urlProperties:urlProperties=mock(urlProperties::class.java)
@豆子
fun urlProperties()=urlProperties
//错误-
//>无法为bean“urlProperties”绑定@ConfigurationProperties。
//>确保@ConstructorBinding未应用于常规bean
//@Bean
//fun urlProperties():urlProperties{
//返回URL属性(
//UrlProperties.FtpProperties(
//url=”ftp://localhost:21"
//          ))
//    }
}
@试验
fun`test fetch file root`(){
`当`(MyTestContext().urlProperties.ftp)
.thenReturn(UrlProperties.FtpProperties(
url=”ftp://localhost:21"
))
assertEquals(“我正在从ftp://localhost:21!",
ftpService.fetchFile())
}
@试验
fun`test fetch文件夹`(){
`当`(MyTestContext().urlProperties.ftp)
.thenReturn(UrlProperties.FtpProperties(
url=”ftp://localhost:21/user/folder"
))
assertEquals(“我正在从ftp://localhost:21/user/folder!",
ftpService.fetchFile())
}
}

解决方法-每次测试时手动定义 唯一的“解决办法”是手动定义所有bean(这意味着我在测试过程中错过了Spring Boot magic),在我看来这更令人困惑

解决方法-手动重新定义每个测试|`src/test/kotlin/com/example/FtpServiceTest2.kt`
import com.example.service.FtpService
导入com.example.service.UrlProperties
导入org.junit.jupiter.api.Assertions.assertEquals
导入org.junit.jupiter.api.beforeach
导入org.junit.jupiter.api.Test
导入org.mockito.mockito
导入org.mockito.mockito.`何时`
导入org.mockito.mockito.doReturn
导入org.mockito.mockito.mock
导入org.springframework.boot.web.client.restemplatebuilder
FtpServiceTest2类{
私有val restTemplate=
RestTemplateBuilder()
.build()
私有lateinit var ftpService:ftpService
私有lateinit var urlProperties:urlProperties
@之前
考试前的乐趣{
urlProperties=mock(urlProperties::class.java)
`当`(urlProperties.ftp)
.thenReturn(UrlProperties.FtpProperties(
url=“默认值”
))
ftpService=ftpService(restTemplate,urlProperties)
}
/**这是唯一允许我重新定义“url”的测试*/
@试验
fun`test fetch文件夹-重定义`(){
urlProperties=mock(urlProperties::class.java)
`当`(urlProperties.ftp)
.thenReturn(UrlProperties.FtpProperties(
url=”ftp://localhost:21/redefine"
))
//重新定义服务
ftpService=ftpService(restTemplate,urlProperties)
assertEquals(“我正在从ftp://localhost:21/redefine!",
ftpService.fetchFile())
}
@试验
fun`testdefault`(){
assertEquals(“我正在从默认值获取文件!”,
ftpService.fetchFile())
}
@试验
fun`test fetch file root`(){
`当`(urlProperties.ftp)
.thenReturn(UrlProperties.FtpProperties(
url=”ftp://localhost:21"
))
assertEquals(“我正在从ftp://localhost:21!",
ftpService.fetchFile())
}
@试验
fun`test fetch文件夹`(){
多雷图恩(
UrlProperties.FtpProperties(
url=”ftp://localhost:21/user/folder"
)).`when`(urlProperties).ftp
assertEquals(“我正在从ftp://localhost:21/user/folder!",
ftpService.fetchFile())
}
@试验
package com.example.service

import org.springframework.boot.context.properties.ConfigurationProperties
import org.springframework.boot.context.properties.ConstructorBinding

@ConstructorBinding
@ConfigurationProperties("url")
data class UrlProperties(val ftp: FtpProperties) {

  data class FtpProperties(
      val url: String,
  )
}