in test with ktlin, how to verify the internal constructor - kotlin

Having a kotlin class
internal class NotificationManager internal constructor(context: Context) : Base(context) {...}
The test was in java and have been working:
#Test
public void verify_internal_Constructor() {
KClass<?> kClass = JvmClassMappingKt.getKotlinClass(NotificationManager.class);
boolean hasPublicConstructor = kClass.getConstructors().stream()
.map(KFunction::getVisibility)
.filter(Objects::nonNull) // package-private and java-protected are null
.anyMatch(kVisibility -> kVisibility.equals(KVisibility.PUBLIC));
assertFalse(hasPublicConstructor);
}
But after convert the test into kotlin, it gets compile error:
fun verify_internal_Constructor() {
val kClass: KClass<*> = NotificationManager::class.java.kotlin
val hasPublicConstructor = kClass.constructors.stream()
.map<KVisibility>(::kotlin.reflect.KCallable.visibility) //<===
.filter { obj: KVisibility? ->
Objects.nonNull(
obj
)
} // package-private and java-protected are null
.anyMatch { kVisibility: KVisibility -> kVisibility == KVisibility.PUBLIC }
assertFalse(hasPublicConstructor)
}
how to map the visibility?

Related

ClassCastException when using Mockito.thenAnswer

I am new to Kotlin. I get exception when trying to use Mockito's thenAnswer method
Controller:
#RestController
class SampleRestController(
val sampleService: SampleService
) {
#PostMapping(value = ["/sample-endpoint"], consumes = [MediaType.APPLICATION_JSON_VALUE], produces = [MediaType.APPLICATION_JSON_VALUE])
fun sampleEndpoint(#RequestBody values: List<String>): ResponseEntity<String> {
val response = sampleService.serviceCall(values)
return ResponseEntity.status(HttpStatus.OK).body(response)
}
}
Service:
#Service
#Transactional
class SampleService {
fun serviceCall(values: List<String>): String {
return values.joinToString("")
}
}
Test:
#ExtendWith(MockitoExtension::class)
internal class SampleRestControllerTest {
#Mock
private lateinit var sampleService: SampleService
private lateinit var mockMvc: MockMvc
private lateinit var objectMapper: ObjectMapper
private lateinit var sampleRestController: SampleRestController
#BeforeEach
fun before() {
MockitoAnnotations.initMocks(this)
objectMapper = ObjectMapper()
.registerModule(JavaTimeModule())
.registerKotlinModule()
sampleRestController = SampleRestController(sampleService)
mockMvc = MockMvcBuilders.standaloneSetup(sampleRestController).build()
}
#Test
fun doTest() {
val testData = listOf("123", "456")
//Mockito.`when`(sampleService.serviceCall(testData)).thenReturn("123456")
//Mockito.`when`(sampleService.serviceCall(testData)).thenAnswer { invocation -> "123456" }
Mockito.`when`(sampleService.serviceCall(testData)).thenAnswer { invocation -> {
val numbers = invocation.getArgument<List<String>>(0)
if ("123" == numbers[0] && "456" == numbers[1]) {
"123456"
} else {
"654321"
}
} }
val result: MvcResult = mockMvc.perform(
MockMvcRequestBuilders.post("/sample-endpoint")
.content(objectMapper.writeValueAsString(testData))
.contentType(MediaType.APPLICATION_JSON_VALUE)
)
.andExpect(status().isOk)
.andReturn()
assertEquals("123456", result.response.contentAsString)
}
}
The unit test is working fine when using the thenReturn() and also when using thenAnswer() without any if condition.
When I try to use thenAnswer with if condition then I get classCastException.
Probably because Kotlin only accepts non-null value? How do I resolve this issue.
Check this.
#Test
fun doTest() {
val testData = listOf("123", "456")
//Mockito.`when`(sampleService.serviceCall(testData)).thenReturn("123456")
//Mockito.`when`(sampleService.serviceCall(testData)).thenAnswer { invocation -> "123456" }
Mockito.`when`(sampleService.serviceCall(testData)).thenAnswer(Answer<Any?> { invocationOnMock: InvocationOnMock ->
val values = invocationOnMock.getArgument<List<String>>(0)
if ("123" == values[0] && "456" == values[1]) {
return#Answer "123456"
}
return#Answer "654321"
})
val result: MvcResult = mockMvc.perform(
MockMvcRequestBuilders.post("/sample-endpoint")
.content(objectMapper.writeValueAsString(testData))
.contentType(MediaType.APPLICATION_JSON_VALUE)
)
.andExpect(status().isOk)
.andReturn()
assertEquals("123456", result.response.contentAsString)
}

Kotlin Mockito Generics

Suppose my class is:
open class TestThis{
#Autowired
private var myService : MyService? = null
fun doMyFunction(){
val result = myService.doSomething("hello world", Function { entry ->
var retVal : Boolean = false
//some processing
retVal
})
}
}
#Service
open class MyService{
fun doSomething(str1 : String, java.util.Function<MyCrap, Boolean>) : List<String>{
//do something here
}
}
#RunWith(MockitoJUnitRunner::class)
class TestThisTest{
#Mock
var myService : MyService? = null
#InjectMocks
var test : TestThis? = null
#Before
fun before(){
val list : List<String> = //init list
//this line causes compilation error due to generics. error 1
Mockito.`when`(myService.doSomething(Mockito.anyString(), Mockito.any(Function::class.java))).thenReturn(list)
//this line also causes compilation error due to generics. error 2
Mockito.`when`(myService.doSomething(Mockito.anyString(), Mockito.any(Function<MyCrap, Boolean>::class.java))).thenReturn(list)
}
}
error 1:
Type inference failed. Expected type mismatch.
error 2:
Only classes are allowed on the left hand side of a class literal
So, how do I mock myService#doSomething?
Getting matchers to work with Kotlin can be a problem.
If you have a method written in Kotlin that does not take a nullable parameter then we cannot match with it using Mockito.any(). This is because it returns null and this is not assignable to a non-nullable parameter.
in Kotlin classes and members are final by default, we need to open them, because mocking is prohibit for final methods
Generic classes mocks rise errors like you described Only classes are allowed on the left hand side of a class literal
All these problems can be resolved via simple MockitoUtils class:
object MockitoUtils {
inline fun <reified T> anyObject(): T {
return Mockito.any(T::class.java) ?: createInstance()
}
inline fun <reified T : Any> createInstance(): T {
return when (T::class) {
Boolean::class -> false as T
Byte::class -> 0.toByte() as T
Char::class -> 0.toChar() as T
Short::class -> 0.toShort() as T
Int::class -> 0 as T
Long::class -> 0L as T
Float::class -> 0f as T
Double::class -> 0.0 as T
else -> createInstance(T::class)
}
}
fun <T : Any> createInstance(kClass: KClass<T>): T {
return castNull()
}
#Suppress("UNCHECKED_CAST")
private fun <T> castNull(): T = null as T
}
Example of usage:
Mockito.`when`(myService!!.doSomething(Mockito.anyString(), MockitoUtils.anyObject())).thenReturn(list)
Service to mock:
open class MyService {
open fun doSomething(str1 : String, func : java.util.function.Function<MyCrap, Boolean>) : List<String>{
return emptyList()
}
}
Service to test:
open class TestThis{
private var myService : MyService? = null
fun doMyFunction() : List<String>? {
val result = myService?.doSomething("hello world", java.util.function.Function { entry ->
var retVal : Boolean = false
//some processing
retVal
} )
return result;
}
}
Test impplementation:
import org.junit.Assert
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.InjectMocks
import org.mockito.Mock
import org.mockito.Mockito
import org.mockito.junit.MockitoJUnitRunner
import kotlin.reflect.KClass
#RunWith(MockitoJUnitRunner::class)
class TestThisTest{
#Mock
var myService : MyService? = null
#InjectMocks
var test : TestThis? = null
#Before
fun before(){
val list : ArrayList<String> = arrayListOf()
list.add("123")
val thenReturn = Mockito.`when`(myService!!.doSomething(Mockito.anyString(), MockitoUtils.anyObject())).thenReturn(list)
}
#Test
fun test() {
val list = test!!.doMyFunction()
Assert.assertTrue(list!!.contains("123"))
}
object MockitoUtils {
inline fun <reified T> anyObject(): T {
return Mockito.any(T::class.java) ?: createInstance()
}
inline fun <reified T : Any> createInstance(): T {
return when (T::class) {
Boolean::class -> false as T
Byte::class -> 0.toByte() as T
Char::class -> 0.toChar() as T
Short::class -> 0.toShort() as T
Int::class -> 0 as T
Long::class -> 0L as T
Float::class -> 0f as T
Double::class -> 0.0 as T
else -> createInstance(T::class)
}
}
fun <T : Any> createInstance(kClass: KClass<T>): T {
return castNull()
}
#Suppress("UNCHECKED_CAST")
private fun <T> castNull(): T = null as T
}
}
Alternative solution:
Another possible solution would be to use a library like mockito-kotlin.
Maven:
<dependency>
<groupId>org.mockito.kotlin</groupId>
<artifactId>mockito-kotlin</artifactId>
<version>4.0.0</version>
<scope>test</scope>
</dependency>
You should not mock "TestThis" when you try to test something inside this Service. If you mock it there is nothing "inside". It is just a mock.
Try instanciating it and then inject a mock of MyService.
It also seems weird where you are writing your Test. Why is a Unit test for MyService in the testclass TestThisTest. You should creat your own Unit test for MyService.

Mockk anonymous class

I'm trying to mock anonymous class created in testInstance Sample:
class SomeClass(val someValue:SomeType) :SomeAnotherClass(){
val anonymousClass = object : AnotherClass{
override anotherMethod() { }
}
override fun someMethod(someValue) = anonymousClass.someMethod(someValue)
}
And test class:
class SomeClassTest {
private val someValue: SomeType = mockk()
private val testInstance = spyk(SomeClass(someValue), recordPrivateCalls = true)
#Test
fun `test method`(){
mockkConstructor(CustomTlsSocketFactory::class)
every { anyConstructed<AnotherClass>().someMethod(someValue) } returns mockk()
testInstance.someMethod(someValue)
verify { anyConstructed<AnotherClass>().someMethod(someValue) }
}
}
And for some reason anonymousClass.someMethod(someValue) is trying to call original method not mockk.
Calling testInstance.anonymousClass.isMock is false

how to pass generic class implementing generic interface to another generic class Kotlin

Hi I am new to programming and trying to implement MVP pattern by passing generic Presenter class LoginPresenter to Generic Model Class LoginUserModel but getting type mismatch error.
on loginUserModel.onAttach(this)
and I am unable to figure out how to pass pass generic interface to another class.
Login Presenter
class LoginPresenter<V : ILoginView>: BasePresenter<V>(), ILoginPresenter<V> {
lateinit var loginUserModel: LoginUserModel<ILoginPresenter<ILoginView>>
lateinit var iLoginPresenter: ILoginPresenter<V>
.........
.........
override fun setupModel() {
iLoginPresenter = this
loginUserModel = LoginUserModel()
// here i am getting error
/**
Type mismatch.
Required:
ILoginPresenter<ILoginView>
Found:
LoginPresenter<V>
*/
loginUserModel.onAttach(this)
}
}
Login Model
class LoginUserModel<P: ILoginPresenter<ILoginView>> : LoginModelContract<P> {
var iLoginPresenter : P? = null
override fun onAttach(ILoginPresenter: P) {
iLoginPresenter = ILoginPresenter
}
}
LoginModelContract
public interface LoginModelContract<P: ILoginPresenter<ILoginView>> {
fun getUsersList(
userName:String,
guid: String
)
fun onAttach(ILoginPresenter: P)
fun onDetatch()
fun getPresenter(): P?
}
You can use two generic statements like below
class LoginUserModel<V: ILoginView, P : ILoginPresenter<V>> : LoginModelContract<V,P> {
var iLoginPresenter : P? = null
override fun onAttach(ILoginPresenter: P) {
iLoginPresenter = ILoginPresenter
}
}
interface ILoginView{
}
interface ILoginPresenter<T>{
fun setupModel()
}
class LoginPresenter<V : ILoginView>: ILoginPresenter<V> {
lateinit var loginUserModel: LoginUserModel<V,ILoginPresenter<V>>
lateinit var iLoginPresenter: ILoginPresenter<V>
override fun setupModel() {
iLoginPresenter = this
loginUserModel = LoginUserModel()
loginUserModel.onAttach(this)
}
}
public interface LoginModelContract<V: ILoginView, P : ILoginPresenter<V>> {
fun onAttach(ILoginPresenter: P)
}

Is it possible to verify at compile time whether the required function is called for the Factory Class in Kotlin?

class ModelFactory {
fun setA() : ModelFactory {
// blabla...
}
fun setB() : ModelFactory {
// blabla...
}
fun setC() : ModelFactory {
// blabla...
}
fun build() : Model {
// An error occurs if any of setA, setB, and setC is not called.
}
}
//example
fun successTest() {
ModelFactory().setA().setB().setC().build() // No error occurs at compile time
}
fun failTest() {
ModelFactory().setA().build() // An error occurs at compile time because setB and setC are not called.
}
It's awkward grammatically, but I think it's been expressed what I want.
I have already implemented an error-raising runtime for this requirement, but I want to check this at compile time.
If possible, I think I should use annotations. But is this really possible at compile time?
With Kotlin, I have been avoiding builder pattern, as we can always specify default values for non-mandatory fields.
If you still want to use a builder pattern, you can use Step builder pattern that expects all mandatory fields to be set before creating the object. Note that each setter method returns the reference of next setter interface. You can have multiple Step builders based on the combination of mandatory fields.
class Model(val a: String = "", val b: String = "", val c: String = "")
class StepBuilder {
companion object {
fun builder(): AStep = Steps()
}
interface AStep {
fun setA(a: String): BStep
}
interface BStep {
fun setB(b: String): CStep
}
interface CStep {
fun setC(c: String): BuildStep
}
interface BuildStep {
//fun setOptionalField(x: String): BuildStep
fun build(): Model
}
class Steps : AStep, BStep, CStep, BuildStep {
private lateinit var a: String
private lateinit var b: String
private lateinit var c: String
override fun setA(a: String): BStep {
this.a = a
return this
}
override fun setB(b: String): CStep {
this.b = b
return this
}
override fun setC(c: String): BuildStep {
this.c = c
return this
}
override fun build() = Model(a, b , c)
}
}
fun main() {
// cannot build until you call all three setters
val model = StepBuilder.builder().setA("A").setB("B").setC("C").build()
}