试图在 Spring Boot 中理解 kotlin DI
Posted
技术标签:
【中文标题】试图在 Spring Boot 中理解 kotlin DI【英文标题】:Trying to understand kotlin DI in Spring boot, at all 【发布时间】:2019-10-03 15:26:54 【问题描述】:由于某种原因,我在 Spring Boot 中掌握 kotlin 风格的 DI 仍然存在巨大问题。尤其是在 JUnit 测试中。
@RunWith(SpringJUnit4ClassRunner::class)
@SpringBootTest(classes = [(ApplicationConfig::class)])
class DataServiceTest
private var dataService: DataService
private var addressRepository: AddressRepository
@Test
fun shouldUpdateCustomerEmail()
dataService.setNewCustomerEmail("1212", ApiEmail("test@test.org"))
我有非常简单的测试。 我尝试了几种注射方式。
private var dataService: DataService
错误:必须初始化属性(有意义)
private lateinit var dataService: DataService
错误:lateinit 属性 dataService 尚未初始化(嗯,是的,我还没有初始化它)
@Autowired
private lateinit var dataService: DataService
错误:找不到“DataService”类型的 bean(为什么?在其他服务中没问题)
class DataServiceTest @Autowired constructor(
private val dataService: DataService
) ...
错误:找不到“DataService”类型的 bean(为什么?在其他服务中没问题)
private var dataService: DataService = DataService()
没有错误。
但不能使用相同的样式为地址注入接口存储库,因为没有接口的构造函数,
所以存储库将未初始化并再次在setNewCustomerEmail()
中抛出错误
DataService 是具有单一方法的 @Service
类(目前),在从 rest 调用时工作正常,但从 @Test
调用时崩溃
@Service
class DataService
@Autowired
private lateinit var addressRepository: AddressRepository
fun setNewCustomerEmail(id: String, email: ApiEmail)
val addressList = addressRepository.findAddressById( id.toInt() )
...
我确实明白为什么会出现大多数这些错误,但是似乎有很多方法可以在 kotlin + spring boot 中 DI 其他依赖项(类和变量),但是对于接下来的每个用例来说似乎都不同,这很好,但我似乎无法掌握何时使用什么。
我如何掌握 kotlin DI?
如何正确注入这个存储库接口?
到目前为止我已经阅读了:
How to use spring annotations like @Autowired in kotlin?
https://www.bignerdranch.com/blog/kotlin-when-to-use-lazy-or-lateinit/
编辑 此外
https://spring.io/guides/tutorials/spring-boot-kotlin/
显示以下代码:
interface UserRepository : CrudRepository<User, Long>
fun findByLogin(login: String): User
然后:
@DataJpaTest
class RepositoriesTests @Autowired constructor(
val entityManager: TestEntityManager,
val userRepository: UserRepository,
val articleRepository: ArticleRepository) ...
这几乎正是我在这里尝试的......但是如果我尝试使用 DataService 执行 @Autowire 构造函数,我会得到错误:再次找不到“DataService”类型的bean。
class DataServiceTest @Autowired constructor(
val dataService: DataService
) ... no beans of type 'DataService' found
如果我尝试在 DataService 中使用 AddressRepository 作为构造函数参数,我现在必须传入一个 Repository,或者使用 @Bean
,我没有?
class DataService @Autowired constructor(
private val AddressRepository: AddressRepository
)
我对此感到非常困惑......
【问题讨论】:
【参考方案1】:我建议使用构造函数注入来为您的服务定义所有依赖项:
@Service
class DataService(private val addressRepository: AddressRepository)
fun setNewCustomerEmail() ...
请注意,您可以在此处省略@Autowired。
要测试您可以使用普通单元测试并自行设置对象:
class DataServiceTest
val mock = mock<AddressRepository>() // e.g. Mockito
val service = DataService(mock)
@Test
fun myTest()
...
您也可以使用 SpringRunner 编写集成测试。然后 Spring 将处理您的服务和存储库的创建和注入。
@RunWith(SpringRunner::class)
@SpringBootTest
class DataServiceTest
@Autowired
lateinit var dataService: DataService
由于您似乎使用 JUnit4 AFAIK,因此无法使用构造函数注入。因此,您需要使用 @Autowired/lateinit 组合。使用 JUnit5 时,应该可以在测试类中定义一个额外的构造函数。
【讨论】:
以上是关于试图在 Spring Boot 中理解 kotlin DI的主要内容,如果未能解决你的问题,请参考以下文章
无法理解 Spring Boot 如何使用 maven 管理集成测试。它是不是使用故障安全插件?
Spring Boot jpa 无法插入包含重音的字符串的行
Spring Boot 中的 PersistenceContext 生命周期