Lateinit 属性模拟对象尚未初始化

J. *_*dam 19 java testing unit-testing mocking kotlin

我正在尝试使用注释 @MockBean 初始化(通过模拟)两个对象

似乎只有当我调用方法模拟(className)时才有效,但由于我想在多个方法上使用模拟类,所以我不想在测试方法中继续重复相同的代码。

这是我的测试课:

@RunWith(MockitoJUnitRunner::class)
class WordServiceTest {

    @MockBean
    lateinit var wordRepositoryMock: WordRepository

    @MockBean
    private lateinit var wordMapperMock: WordMapper

    @Test
    fun findAllTest() {
        // Error: lateinit property wordRepositoryMock has not been initialized
        val wordService = WordService(wordRepositoryMock, wordMapperMock)
        `when`(wordRepositoryMock.findAll()).thenReturn(listOf(
                WordEntity(UUID.randomUUID(), "xxx"),
                WordEntity(UUID.randomUUID(), "xxx")))
        assertEquals(2, wordService.findAll().size)
    }

    @Test
    fun wordExistsTest() {
        // This works fine
        val wordRepositoryMock = mock(WordRepository::class.java)
        val wordMapperMock = mock(WordMapper::class.java)
        val wordService = WordService(wordRepositoryMock, wordMapperMock)
        val word = "xxx"
        `when`(wordRepositoryMock.existsWordEntityByName(word)).thenReturn(true)
        assertEquals(true, wordService.wordExists(word))
    }
}
Run Code Online (Sandbox Code Playgroud)

我不想使用 Spring Boot @Autowired 注释,因为我的 Spring 应用程序需要我不想加载的上下文。

我收到的错误:

lateinit property wordRepositoryMock has not been initialized
kotlin.UninitializedPropertyAccessException: lateinit property wordRepositoryMock has not been initialized
Run Code Online (Sandbox Code Playgroud)

依赖项:

dependencies {
    ...
    testImplementation("org.springframework.security:spring-security-test")
    testImplementation ('org.springframework.boot:spring-boot-starter-test') 
    testImplementation("org.junit.jupiter:junit-jupiter:5.6.2")
    testImplementation "org.junit.jupiter:junit-jupiter-params:5.5.2"
    testImplementation "org.junit.jupiter:junit-jupiter-api:5.6.2"
    testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:5.6.2"
    testImplementation("io.rest-assured:spring-mock-mvc:4.0.0")
    testImplementation("io.mockk:mockk:1.9.3")
    testImplementation "org.testcontainers:postgresql:1.11.3"
    testImplementation "org.springframework.kafka:spring-kafka-test:2.2.7.RELEASE"
    runtimeOnly('org.postgresql:postgresql')
    developmentOnly 'org.springframework.boot:spring-boot-devtools'
    testImplementation "org.mockito:mockito-junit-jupiter:3.3.3"
}
Run Code Online (Sandbox Code Playgroud)

J. *_*dam 23

我通过在setUp()中调用initMocks方法解决了这个问题

@BeforeEach
    fun setUp() {
        MockitoAnnotations.openMocks(this)
        ....
    }
Run Code Online (Sandbox Code Playgroud)


Jak*_*las 13

MockitoJUnitRunner与注释一起使用@Mock

@MockBean来自 Spring,因此您需要使用@SpringRunner.

但是,您的示例似乎不需要 Spring,因此您可以切换到@Mock

@RunWith(MockitoJUnitRunner::class)
class WordServiceTest {

    @Mock
    private lateinit var wordRepositoryMock: WordRepository

    @Mock
    private lateinit var wordMapperMock: WordMapper
}
Run Code Online (Sandbox Code Playgroud)

如果升级到 Junit5,您可以进一步改进(我只在 Junit5 中进行了测试)。构造函数参数是一个很好的替代方案lateinit

@ExtendWith(MockitoExtension::class)
class WordServiceTest(
    @Mock val wordRepositoryMock: WordRepository,
    @Mock val wordMapperMock: WordMapper
) {

}
Run Code Online (Sandbox Code Playgroud)


Eur*_*tré 11

对于因已弃用而出现的功能initMocks(this),我注意到有一个较新的功能可以执行相同的操作:

@BeforeEach
fun setUp() {
    MockitoAnnotations.openMocks(this)
        ....
}
Run Code Online (Sandbox Code Playgroud)