I'm trying to initialize (by mocking) two objects with the annotation @MockBean
It seems only to work if i call the method mock(className), but since i want to use the mocked class on multiple methods i don't want to keep repeating the same code in my test methods.
This is my test class:
@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))
}
}
I don't want to use the Spring Boot @Autowired annotation because my spring application requires contexts which i don't want to load.
The error i'm getting:
lateinit property wordRepositoryMock has not been initialized
kotlin.UninitializedPropertyAccessException: lateinit property wordRepositoryMock has not been initialized
Dependencies:
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"
}
In order to create a "lateInit" variable, we just need to add the keyword "lateInit" as an access modifier of that variable. Following are a set of conditions that need to be followed in order to use "lateInit" in Kotlin. Use "lateInit" with a mutable variable. That means, we need to use "var" keyword with "lateInit".
You can check if the lateinit variable has been initialized or not before using it with the help of isInitialized() method. This method will return true if the lateinit property has been initialized otherwise it will return false.
The lateinit keyword allows you to avoid initializing a property when an object is constructed. If your property is referenced before being initialized, Kotlin throws an UninitializedPropertyAccessException , so be sure to initialize your property as soon as possible.
I solved this problem by calling initMocks method in setUp()
@BeforeEach
fun setUp() {
MockitoAnnotations.initMocks(this)
....
}
MockitoJUnitRunner
works with the @Mock
annotation.
@MockBean
is coming from Spring so you need to use the @SpringRunner
.
However, it looks like your examples don't need Spring, so you can switch to @Mock
:
@RunWith(MockitoJUnitRunner::class)
class WordServiceTest {
@Mock
private lateinit var wordRepositoryMock: WordRepository
@Mock
private lateinit var wordMapperMock: WordMapper
}
There's a further improvement you could make if you upgraded to Junit5 (I only tested it in Junit5). Constructor arguments are a good alternative to lateinit
:
@ExtendWith(MockitoExtension::class)
class WordServiceTest(
@Mock val wordRepositoryMock: WordRepository,
@Mock val wordMapperMock: WordMapper
) {
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With