#Autowired member not initialized in a Junit 5 test written in Kotlin - kotlin

I can't get an #Autowired member to be initialized in a JUnit 5 test. Here is the test:
import org.amshove.kluent.`should be equal to`
import org.junit.Test
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.context.SpringBootTest
import org.springframework.boot.test.context.TestConfiguration
import org.springframework.context.annotation.Bean
#SpringBootTest
class SnackQueryResolverTest {
#TestConfiguration
class SnackQueryResolverTestConfig {
#Bean
fun snackQueryResolverFactory() = SnackQueryResolver()
}
#Autowired
private lateinit var snackQueryResolver: SnackQueryResolver
#Test
fun `snacks`() {
val snacks = snackQueryResolver.snacks()
snacks.size `should be equal to` 5
}
}
When the test is run I receive the error:
kotlin.UninitializedPropertyAccessException: lateinit property snackQueryResolver has not been initialized
If I eliminate the #Autowired and instantiate the bean during construction, the test runs fine:
#SpringBootTest
class SnackQueryResolverTest {
private val snackQueryResolver: SnackQueryResolver = SnackQueryResolver()
#Test
fun `snacks`() {
val snacks = snackQueryResolver.snacks()
snacks.size `should be equal to` 5
}
}
What am I missing?

Turns out a small error was causing the issue - careless with IDE code completion. For #Test, I was importing:
import org.junit.Test
instead, this needs to be used for JUnit 5 tests:
import org.junit.jupiter.api.Test

Related

How to call method Reference in map

I create a class ApUtils . Define two methods in that class . I want
use that two methods in my service class inside the map function by
the help of method reference ,But I am getting un excepted error while
calling these two methods
service.kt
package com.nilmani.reactivespringdemo.services
import com.nilmani.reactivespringdemo.Utils.AppUtils
import com.nilmani.reactivespringdemo.dto.ProductDto
import com.nilmani.reactivespringdemo.entity.Product
import com.nilmani.reactivespringdemo.repository.ProductRepository
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.stereotype.Service
import reactor.core.publisher.Flux
import reactor.core.publisher.Mono
#Service
class ProductService {
#Autowired
private lateinit var productRepository: ProductRepository
fun getProduct():Flux<ProductDto>{
return productRepository.findAll().map(obj: AppUtils -> obj.entityToDto(product))
}
fun getProduct(id:String):Mono<ProductDto>{
return productRepository.findById(id).map{ obj: AppUtils, product: Product -> obj.entityToDto(product) }
}
}
AppUtils.kt
package com.nilmani.reactivespringdemo.Utils
import com.nilmani.reactivespringdemo.dto.ProductDto
import com.nilmani.reactivespringdemo.entity.Product
import org.springframework.beans.BeanUtils
class AppUtils {
fun entityToDto(product: Product):ProductDto{
val productDto = ProductDto()
BeanUtils.copyProperties(product,productDto)
return productDto
}
fun dtoToEntity(productDto: ProductDto):Product{
val product = Product()
BeanUtils.copyProperties(productDto,product)
return product
}
}
How to call these two function in my service class using method reference
If you change AppUtils to a singleton using Kotlin's object keyword:
object AppUtils { ... }
then you can use method references like so:
fun getProduct(id:String) = productRepository.findById(id).map(AppUtils::entityToDto)

How to mock an SQLiteOpenHelper

I am trying to mock an SQLiteOpenHelper class in instrumented tests so whenever any fragment tries to get information from the database it returns a generic result. However, I keep getting an error saying:
org.mockito.exceptions.base.MockitoException: Cannot mock/spy class
com.example.cleaningschedule.helpers.DatabaseHandler Mockito cannot
mock/spy because :
final class
at com.example.cleaningschedule.ToDoListInstrumentedTest.oneTask(ToDoListInstrumentedTest.kt:81)
The test class is:
#RunWith(AndroidJUnit4::class)
class ToDoListInstrumentedTest {
#Rule
#JvmField var activityRule: ActivityTestRule<MainActivity> = ActivityTestRule(MainActivity::class.java)
private fun getActivity() = activityRule.activity
#After
fun tearDown() {
InstrumentationRegistry.getInstrumentation().getTargetContext().deleteDatabase("TaskDatabase")
}
#Test
fun oneTask() {
val mock = mock(DatabaseHandler::class.java)
`when`(mock.getTasks()).thenThrow()
onView(withId(R.id.taskName)).check(matches(isDisplayed()))
}
}
The class I am trying to mock is:
class DatabaseHandler(context: Context): SQLiteOpenHelper(context, DATABASE_NAME, null, DATABASE_VERSION) {
companion object {
private const val DATABASE_VERSION = 5
private const val DATABASE_NAME = "TaskDatabase"
...
}
override fun onCreate(db: SQLiteDatabase?) {
...
}
override fun onUpgrade(db: SQLiteDatabase?, oldVersion: Int, newVersion: Int) {
...
}
fun getTasks(): MutableList<Pair<MutableList<String>, MutableList<Room>>> {
...
}
}
I have looked at several other similar questions but none have helped:
Error mocking Class which hold reference to SQLiteOpenHelper
Mock final class in java using mockito library - I had a lot of issues with import PowerMock
How to mock a final class with mockito - I have added the dependency and created the file with the mock-maker-inline line as suggested in the answers put I still get the same error. I also tried the answer that suggested Mockito.mock(SomeMockableType.class,AdditionalAnswers.delegatesTo(someInstanceThatIsNotMockableOrSpyable)) but this gave me a 'Not enough information to infer type variable T' error
Mock final class with Mockito 2
Mockito cannot mock/spy because : Final Class
Cannot mock/spy class java.util.Optional
I will made an Interface :
public interface ContainerHandler {
MutableList<Pair<MutableList<String>, MutableList<Room>>> getTasks();
}
Then I made DatabaseHandler inherit this interface, I call Mockito's mock function with the Interface.
val mock = mock(ContainerHandler::class.java)
`when`(mock.getTasks()).thenThrow()
And finally I inject my mock into the tested class.

What is the reason for an UninitializedPropertyAccessException in #SpringBootTest with MockK and Kotlin?

I am trying to use MockK 1.10.2 with Kotlin 1.4.10 and #SpringBootTest (Spring Boot 2.2.2.RELEASE) and I can't get it run because of a
OpenJDK 64-Bit Server VM warning: Sharing is only supported for boot loader classes because bootstrap classpath has been appended
2020-11-05 15:00:37.878 WARN --- [ main] i.m.p.j.t.InliningClassTransformer : Failed to transform class java/lang/Object
java.lang.IllegalArgumentException: Unsupported class file major version 59
at net.bytebuddy.jar.asm.ClassReader.<init>(ClassReader.java:195)
at net.bytebuddy.jar.asm.ClassReader.<init>(ClassReader.java:176)
at net.bytebuddy.jar.asm.ClassReader.<init>(ClassReader.java:162)
at net.bytebuddy.utility.OpenedClassReader.of(OpenedClassReader.java:86)
at net.bytebuddy.dynamic.scaffold.TypeWriter$Default$ForInlining.create(TypeWriter.java:3394)
at net.bytebuddy.dynamic.scaffold.TypeWriter$Default.make(TypeWriter.java:1933)
at net.bytebuddy.dynamic.scaffold.inline.RedefinitionDynamicTypeBuilder.make(RedefinitionDynamicTypeBuilder.java:217)
at net.bytebuddy.dynamic.scaffold.inline.AbstractInliningDynamicTypeBuilder.make(AbstractInliningDynamicTypeBuilder.java:120)
at net.bytebuddy.dynamic.DynamicType$Builder$AbstractBase.make(DynamicType.java:3404)
at io.mockk.proxy.jvm.transformation.InliningClassTransformer.transform(InliningClassTransformer.kt:77)
at java.instrument/java.lang.instrument.ClassFileTransformer.transform(ClassFileTransformer.java:246)
at java.instrument/sun.instrument.TransformerManager.transform(TransformerManager.java:188)
at java.instrument/sun.instrument.InstrumentationImpl.transform(InstrumentationImpl.java:563)
at java.instrument/sun.instrument.InstrumentationImpl.retransformClasses0(Native Method)
at java.instrument/sun.instrument.InstrumentationImpl.retransformClasses(InstrumentationImpl.java:167)
at io.mockk.proxy.jvm.transformation.JvmInlineInstrumentation.retransform(JvmInlineInstrumentation.kt:28)
at io.mockk.proxy.common.transformation.RetransformInlineInstrumnetation$execute$1.invoke(RetransformInlineInstrumnetation.kt:19)
at io.mockk.proxy.common.transformation.RetransformInlineInstrumnetation$execute$1.invoke(RetransformInlineInstrumnetation.kt:6)
at io.mockk.proxy.common.transformation.ClassTransformationSpecMap.applyTransformation(ClassTransformationSpecMap.kt:41)
at io.mockk.proxy.common.transformation.RetransformInlineInstrumnetation.execute(RetransformInlineInstrumnetation.kt:16)
at io.mockk.proxy.jvm.ProxyMaker.inline(ProxyMaker.kt:88)
at io.mockk.proxy.jvm.ProxyMaker.proxy(ProxyMaker.kt:30)
kotlin.UninitializedPropertyAccessException: lateinit property taService has not been initialized
exception. (The same happens if I use tmpService. It doesn't matter if the imported service is in the same or a different package as the test class.)
As you can see from the code of my test class I already played around a lot but without any success so far.
package com.xxx.emr.tm
import com.xxx.data.emr.model.PatientAssignment
import com.xxx.data.tm.TMPService
import com.xxx.data.tm.model.MyType
import com.xxx.data.tm.model.MyTypeCode
import com.xxx.data.tm.model.UserAction
import com.xxx.emr.service.model.AuthenticatedUser
import io.mockk.every
import io.mockk.impl.annotations.InjectMockKs
import io.mockk.impl.annotations.SpyK
import io.mockk.junit5.MockKExtension
import io.mockk.mockk
import io.mockk.mockkObject
import io.mockk.verify
import org.junit.Test
import org.junit.jupiter.api.extension.ExtendWith
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.context.SpringBootTest
#ExtendWith(SpringExtension::class, MockKExtension::class)
#SpringBootTest // (classes = [com.xxx.emr.service.MyServiceSpringBoot::class])
// #RunWith(SpringJUnit4ClassRunner::class)
// #ActiveProfiles("test")
// #EnableAutoConfiguration
// #AutoConfigureMockMvc
class MyTest {
// (
// val tmpService: TMPService,
// val taService: TaService
// )
// #InjectMockKs
// #Autowired
// #SpyK
#MockK
private lateinit var tmpService: TMPService
#InjectMockKs
#Autowired
private lateinit var taService: TaService
#Test
fun assignAToB() {
MockKAnnotations.init(this, relaxUnitFun = true)
val vId = "xxx"
val authUser: AuthenticatedUser = AuthenticatedUser.mockedUser()
val userAction = UserAction(
userId = "user_id",
actionCode = ActionType.GET_IT,
sessionId = "sessionId"
)
val xxx = MyType(
MyTypeCode.ABC.value,
MyTypeCode.ABC.name,
)
val actionResult = UserActionResult(hashMapOf("success" to true))
// every { tmpService.getXxx(any()) } returns xxx
verify( exactly = 1 ) {
tmpService.doSomething(any(), any(), any())
}
verify( exactly = 1 ) {
taService.dowhatYouWant(„vId", authUser, userAction)
}
}
Autowiring does not work...so what is my fault? How can I make the test run at all?
I think you should initialize your mocks first, by adding this in your test file for example:
#org.springframework.test.context.event.annotation.BeforeTestMethod
fun initMocks() {
org.mockito.MockitoAnnotations.initMocks(this)
}
I created a post on another thread about how to setup unit testing, comparable with your requirements:
https://stackoverflow.com/a/64669499/7919904

Kotlin coroutine in Spring DataJpaTest

In a spring Boot service we have a new Kotlin coroutine implementation which works nicely.
However, when trying to test it the JpaRepository seems to get "truncated" when accessed on a coroutine block. here is a simplified portion of the code:
import kotlinx.coroutines.*
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.extension.ExtendWith
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest
import org.springframework.data.jpa.repository.JpaRepository
import org.springframework.test.context.ContextConfiguration
import org.springframework.test.context.junit.jupiter.SpringExtension
import javax.persistence.*
#ExtendWith(SpringExtension::class)
#ContextConfiguration(classes = [SpringTestConfig::class])
#DataJpaTest
class BadRepoTest(#Autowired val testedRepository: TestRepository) {
#Test
fun testRepo() {
testedRepository.saveAndFlush(TestEntity())
println("count at start: ${testedRepository.count()} and $testedRepository")
runBlocking {
runCodeAsync().await()
}
println("count post async code: ${testedRepository.count()} and $testedRepository")
}
fun runCodeAsync(): Deferred<Unit> {
return GlobalScope.async {
println("count in async code: ${testedRepository.count()} and $testedRepository")
}
}
}
interface TestRepository : JpaRepository<TestEntity, Int>
#Entity
#Table(name = "test")
data class TestEntity(
#Id #GeneratedValue(strategy = GenerationType.IDENTITY) val id: Int? = null
)
I would expect the repository to contain a single entity at all time during the test run, but the code prints:
count at the start: 1 and SimpleJpaRepository#40d04cf8
count in async code: 0 and SimpleJpaRepository#40d04cf8
count post async code: 1 and SimpleJpaRepository#40d04cf8
Could you please advise?

JUnit5 SpringBootTest NullPointerException when testing Service

I am following a tutorial for unit testing a Service, and I am attempting to use JUnit5 instead of JUnit4 (which is what the tutorial uses). The test works fine when I follow the tutorial exactly with JUnit4, but I get a NullPointerException with JUnit5.
The repository:
public interface CourseRepo extends CrudRepository<Course, Long> {}
The service:
#Service
public class CourseService {
private final CourseRepo courseRepo;
public CourseService(CourseRepo courseRepo) {
this.courseRepo = courseRepo;
}
public Course save(Course course) {
Course newCourse = courseRepo.save(course);
return newCourse;
}
}
The test:
package com.elovell.blackboard.service;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.when;
import com.elovell.blackboard.domain.Course;
import com.elovell.blackboard.repository.CourseRepo;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
#ExtendWith(MockitoExtension.class)
#SpringBootTest(webEnvironment = WebEnvironment.NONE)
public class CourseServiceTest {
#Mock
public CourseRepo courseRepo;
#InjectMocks
public CourseService courseService;
#BeforeEach
public void setUp() {
MockitoAnnotations.initMocks(this);
}
#Test
public void testSaveCourse() {
Course mockCourse = new Course();
mockCourse.setPk1(1L);
mockCourse.setCourseId("ENGL101");
when(courseRepo.save(any(Course.class))).thenReturn(mockCourse);
// save(null) should still return mockCourse
Course newCourse = courseService.save(null);
assertEquals("ENGL101", newCourse.getCourseId());
}
}
Here is the first few lines of the Exception:
java.lang.NullPointerException
at com.elovell.blackboard.service.CourseServiceTest.testSaveCourse(CourseServiceTest.java:44)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
The test and dependencies portion of my build file:
test {
useJUnitPlatform {
includeEngines 'junit-jupiter'
}
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-web'
runtimeOnly 'com.h2database:h2'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testImplementation("org.junit.jupiter:junit-jupiter-api:5.5.1")
testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.1.0")
testCompile 'org.mockito:mockito-junit-jupiter:2.23.4'
}
This looks like you trying to mix an integration test with unit tests.
When you use the #SpringBootTest annotation then SpringExtension for Junit5 starts an application context before running your test, and to make mocks in tests you need to use #MockBean annotation instead of #Mock & #InjectMocks. This is a different scope of tests.
As I see, you need just a unit test and you can remove the SpringBootTest annotation.
By the way, I think you got NPE because of you any(Course.class) in when(courseRepo....
Try to use isNull() or any() (without specification concrete class).