Is there a way to mock the invocation of a secondary constructor of a Kotlin data class using mockk - kotlin

From the documentation of mockk.io regarding the mocking capabilities of constructors I can see the following:
class MockCls(private val a: Int = 0) {
constructor(x: String) : this(x.toInt())
fun add(b: Int) = a + b
}
mockkConstructor(MockCls::class)
every { constructedWith<MockCls>().add(1) } returns 2
As far as I understood it is possible to mock the construction of an object and get a result for an executed method.
What I would like to have is e.g. the following
data class MyDataClass(val first: String) {
constructor(anotherDataClass: AnotherDataClass) : this(
first = anotherDataClass.second
)
}
data class AnotherDataClass(val second: String)
mockkConstructor(MyDataClass::class)
every { constructedWith<MyDataClass>() } returns mockk<MyDataClass>
or
every { anyConstructed<MockCls>() } returns mockk<MyDataClass>
In the end, I want to bypass the construction and directly return a constructed mock and not first execute a method and return the result.

Avoiding constructor execution while mocking not currently (<=1.12.0) possible by design (https://github.com/mockk/mockk/issues/515)
If you really want to capture instance while doing constructor mocking, you can get away with this:
val myMockedInstance: MyClass = MockKGateway.implementation().constructorMockFactory.mockPlaceholder(
MyClass::class,
args = arrayOf<Matcher<*>>(
EqMatcher(dummyParamOfMine)
) as Array<Matcher<*>>
)

Related

Is there a way to make the first digit of int always start with 1 in Kotlin

Let's say I have the following class constructor:
class Car(val brand: Brand,val modelName: String, val version: Int){}
If for example, I want the version number to always start with 1. Is there a way to manipulate it in the class body to achieve this ?
Meaning:
val firstdigit:Int = abs(version).ToString().Substring(0,1)
And then parse it to Int. But how to replace the original first digit after that?
I'm just learning Kotlin and I got a bit stuck with this
Is this what you had in mind?
class Car(val brand: Brand, val modelName: String) {
val version = getNextVersion()
companion object {
private var nextVersion = 0
private fun getNextVersion(): Int {
nextVersion++
if (nextVersion.toString()[0] != '1') {
nextVersion = (10.0.pow(ceil(log10(nextVersion.toDouble())))).toInt()
}
return nextVersion
}
}
}
You already said in the comments that you want the number to increment per instance, so the caller shouldn't be providing that number in the first place really! But just generally, here's two approaches to sanitising your input parameters:
1) Make it the caller's responsibility to provide valid data
init {
require(version.toString().first() == '1') { "Needs to start with 1 thanks" }
}
require throws an IllegalArgumentException if it fails, which is the standard exception for "the value of this argument is invalid". Should the class be responsible for taking bad data and trying to "fix" it, or should the caller be handling that - and maybe not constructing an instance at all if it doesn't have valid data?
2. create a newInstance function that uses valid data, and keep the constructor private
class Thing private constructor(val number: Int){
companion object {
fun newInstance(num: Int): Thing {
return Thing(abs(num))
}
}
}
fun main() {
Thing.newInstance(-2).let { println(it.number)}
}
If it makes sense for the class itself to sanitise the input parameters, you can delegate construction to a function that takes care of that, and prevent things from calling the constructor directly with potentially bad data.
This can cause issues with e.g. serialisation libraries (which want to call the constructor directly) but in that case you could leave the constructor public, and just advise callers to call newInstance instead. Not ideal, but it's an option!

How to convert String to Function in Kotlin?

fun getApple(): Apple = {...}
fun setOrange(orange: Orange) {...}
val funMap = hashMapOf("getApple" to this::getApple, "setOrange" to this::setOrange)
funMap["getApple"]()
I want to put the method on the map.
Then get the method by string, but can't be invoked if function type different. Any other way to convert the string to function?
---- update ----
I used to use the java reflection before, I am looking for a more efficient way
It's possible, but your map has type Map<String, KFunction<Any>>. For KFunction you have method .call and .callBy(Map<KParameter, Any>). So, see this example (I've also added logging when function invoked):
class StackStringFunction {
data class Apple(val size: Int = 1)
data class Orange(val color: String = "orange")
fun getApple(): Apple {
println("Calling getApple()")
return Apple()
}
fun setOrange(orange: Orange) {
println("Calling setOrange(Orange) with param $orange")
}
val funMap = hashMapOf("getApple" to this::getApple, "setOrange" to this::setOrange)
}
// Invocation example:
with(StackStringFunction()) {
this.funMap["getApple"]?.call()
this.funMap["getApple"]?.callBy(mapOf())
this.funMap["setOrange"]?.call(StackStringFunction.Orange())
this.funMap["setOrange"]?.callBy(mapOf(this.funMap["setOrange"]!!.parameters[0]to StackStringFunction.Orange()))
}
And the output:
Calling getApple()
Calling getApple()
Calling setOrange(Orange) with param Orange(color=orange)
Calling setOrange(Orange) with param Orange(color=orange)
As you see, via ::sth you obtain not a lambda, but KFunction, and using KFunction interface you are able to call those methods.

Subclass var initialization step and OOP structure design

The abstract super class Parent has abstract method extract(Int), getting the value a from primary constructor, and submit it to that method extract(a).
abstract class Parent ( val a : Int ) {
abstract fun extract ( i : Int )
init {
// call overriden extract(Int)
extract ( a )
}
}
The sub class Child defines the method extract(Int), sending the value b to the Parent's constructor, then the super class Parent calling extract(Int) to set that value to Child's variable x.
class Child ( b : Int ) : Parent ( b ) {
// initialize x variable to -1
var x : Int = -1
override fun extract ( i : Int ) {
// set x to given int
x = i
}
}
Testing:
println ( Child ( 10 ).x )
And got:
-1
Now, try adding init{} of the sub class Child
init {
x = -2
}
Testing again:
println ( Child ( 10 ).x )
And got:
-2
Seemingly, the init{} of sub class Child is done after the super class Parent's construction.
Should the extract(Int) be overridden ann called by all sub classes, rather than by the super class?
I am not sure what you mean by "super class Child", but it seems you may be confused of the order of derived classes. Here is a really good example that shows the order. It has a code snippet that you can run on the site.
Generally speaking this kind of initializer interaction is frowned upon, since the exact order of operations, while well defined, is often counter-intuitive.
Specifically, what I believe is happening here, might be more clear using the more verbose explicit-constructor syntax in kotlin. You're code is an abbreviated version of this (note, this is legal kotlin):
abstract class Parent {
val a: Int
constructor(a: Int){
this.a = a
extract(a)
}
abstract fun extract ( i : Int )
}
class Child: Parent {
var x : Int
constructor(b: Int): Parent(b) {
//super.constructor(b) fires here
// initialize x variable to -1
x = -1
}
override fun extract (i : Int) {
// set x to given int
x = i
}
}
thus, as I hope is now a little more clear, a pseudo-call-trace is like this:
enter Child.constructor(10)
enter Parent.constructor(10)
assign 10 to this#Parent.a
enter this.extract(10) => V-Table resolves Child.extract()
assign 10 to this#Child.x
extract returns
Parent.constructor returns
assign -1 to this#Child.x this is probably your point of confusion
Child.constructor returns
What you can do
Generally speaking, when you encounter confusing initialization flows, the answer on the JVM is to formalize the complex initialization in another method, rather than in more init or constructors.
In kotlin the simplest way to do this --and a strategy used by many many libraries-- is to create a static factory method.
abstract class Parent(val a: Int) {
//...
}
class Child private constructor(var x: Int): Parent(x) {
companion object {
fun makeChild(unextracted: Int) {
val extracted = extract(unextracted)
return Child(extracted)
}
// a first good step is to make `extract` referentially transparent
// aka pure
// IE all of its function is provided in its return type
fun extract (i : Int): Int {
return i //do appropriate transforms.
//note, if you need multiple return values here, consider Pairs or Triples.
}
}
}
Note, kotlin provides some syntax sugar for this, you can override the invoke operator:
class Child { companion object { operator fun invoke(x: Int) { ... } } }
which means that instead of makeChild (eg Child.makeChild(10)) to call your factory function you to use ~constructor syntax (Child(10)).
Even more generally, if you find yourself running into this problem under an IOC container which, for whatever reason, must use initializer flow, I would encourage you to refactor your IOC consumers to use old-fashioned java factories. I'll need more details to elaborate here.

is it possible to add a template to the getter/setter of a data class?

for example , I want to change all setters this way:
this.a = StringUtils.trim(a);
If it's a java bean, I can do this by modifying the code generating template of the ide. But Intellij seems not support to atomically add getter/setter for kotlin data class.
Is there a way to do this?
There is not a way to do this as of Kotlin 1.1.
A Kotlin data class, for the most part, is a class "to do nothing but hold data".
I think the closest you can get is to validate your data upon class initialization and make your data class properties read-only values. e.g.:
data class Data(val a: String) {
init {
require(a == a.trim())
}
}
The following won't throw an exception:
val a = Data("ab")
val b = a.copy(a = "abc")
While the following will:
val c = a.copy(a = "abc ")
It looks like if you declare the property as private, you can create your own getter/setters for accessing it. This example works for me.
fun main(args: Array<String>) {
var t = test("foo")
t.setHello("bar")
println(t)
}
data class test(private var hello: String) {
fun setHello(blah: String) {
this.hello = blah
}
}
But you will still have an issue when the property is passed in to the constructor. You will probably need to rethink how you are doing this, either declaring the field private and trimming it in the getter, or not using a data class for this instance.

How do I initialize a final field in Kotlin?

Let's say I declared a final field with private final String s (Java) or val s (Kotlin). During initialization I want to initialize the field with the result of a call to a remote service. In Java I would be able to initialize it in the constructor (e.g. s = RemoteService.result()), but in Kotlin I can't figure out how to do that because as far as I can tell the field has to be initialized in the same line it's declared. What's the solution here?
You can set val value in init block:
class MyClass {
val s: String
init {
s = "value"
}
}
You can also initialize the value with by lazy the value will be initialized the first time it is referred. An example
val s by lazy { RemoteService.result() }
kotlin will guess the type of s from the return type of the expression.
You can use run:
class MyClazz {
val prop = run {
// do stuff
// do stuff again
123 // return expression
}
}
From the docs (emphasis is mine):
Besides calling run on a receiver object, you can use it as a non-extension function. Non-extension run lets you execute a block of several statements where an expression is required.
It has been possible to do it simply like this since the very first official stable release of Kotlin:
class MyClass {
val s = RemoteService.result()
}