【问题标题】:Trying to understand kotlin DI in Spring boot, at all试图在 Spring Boot 中理解 kotlin DI
【发布时间】:2023-03-05 10:53:01
【问题描述】:

由于某种原因,我在 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
)

我对此感到非常困惑......

【问题讨论】:

    标签: spring-boot kotlin dependency-injection


    【解决方案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 时,应该可以在测试类中定义一个额外的构造函数。

    【讨论】:

      猜你喜欢
      • 2015-12-20
      • 2020-12-29
      • 2019-03-07
      • 1970-01-01
      • 2020-12-04
      • 1970-01-01
      • 2019-07-29
      • 2022-01-27
      • 2020-09-17
      相关资源
      最近更新 更多