in the doc of scalamock, it is said that:
mocking classes, traits and case classes
is one of the feature supported.
I have the following case class:
case class Thing(private val item: Item)
When i do:
val item = mock[Thing]
I get the following error:
Error:(18, 24) not enough arguments for constructor Thing:
(item: org.dspace.content.Item)org.iadb.poolpartyconnector.dspaceutils.Thing.
Unspecified value parameter item.
val item = mock[Thing]
^
I know i could implement an interface for it, but in any case, this would help me better understand how to mock a case class/a class that has constructor.
Many thanks,
Maatari
Currently, you cannot mock classes that do not have a default constructor defined.
You can workaround it by creating a subclass that has default constructor defined and mocking that subclass:
class MockableThing extends Thing(null)
val item = mock[MockableThing]
Related
I am still learning kotlin, and I am curious how is it possible that mockk is able to return some object T wrapped in Result<T>. For better understanding let analyse below example:
We have such method definition
fun save(toSave : Entity): Result<Entity>
when we mock such method using returnArguments like it is done below:
every { mocked.save(any()) } returnsArgument 0
Then method returns Result<Entity>, but logic says that Entity should be returned.
Looking into declaration of returnsArgument there is casting to generic type which in our case is Result<Entity>, but when I tried to do it in plain I had casting exception.
I assume some magic happens inside, but what magic is responsible for such thing?
Would it be done with any wrapping object or it is specific only to Result?
Result<T> is a value class and mockk has a value class support.
After many internal steps returnsArgument will wrap the argument n with the specified value class and will return it.
Would it be done with any wrapping object or it is specific only to Result?
All value classes are supported, not just Result<T>.
// supported
#JvmInline
value class ValueWrapper<out T> (val something: Any?)
// not supported
class SomeWrapper<out T> (val something: Any?)
Hope it helps.
Given a domain class with a parameterless constructor, how do we get a reference to that constructor through the Reflection API?
Consider for example a Student data class, such as:
data class Student(var nr: Int = 0, var name: String? = null)
Notice, we can confirm the presence of the parameterless constructor through javap that shows:
public pt.isel.Student(int, java.lang.String);
descriptor: (ILjava/lang/String;)V
public pt.isel.Student(int, java.lang.String, int, kotlin.jvm.internal.DefaultConstructorMarker);
descriptor: (ILjava/lang/String;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
public pt.isel.Student();
descriptor: ()V
Yet, none of the following approaches returns the parameterless constructor:
Approach 1 - primaryConstructor:
val constructor = Student::class.primaryConstructor
Approach 2 - All constructors declared in the class:
// java.util.NoSuchElementException: Collection contains no element matching the predicate
val constructor = Student::class.constructors.first { it.parameters.isEmpty() }
Alternatively, we can proceed via Java Reflection that works fine, but it should not be necessary such detour:
val constructor = Student::class.java.getDeclaredConstructor()
Second, why do we need that? Because we want to instantiate a domain class at runtime. Yes, we know that createInstance() of KClass do that job. But it throws IllegalArgumentException: Class should have a single no-arg constructor if there is no parameterless constructor.
Thus, we would like to check before-hand if we could call the createInstance() with no exceptions.
The parameterless constructor here only exists in the compiled Java class, and not in your Kotlin code. As far as Kotlin code is concerned, your Student class has one single constructor, with 2 optional parameters.
The Kotlin reflection API is designed to be platform-independent, so you have to use Java reflection to get the parameter constructor.
If you just want to see if you can call createInstance safely, you can just check if the class has a single constructor whose parameters are all optional. This is documented:
Creates a new instance of the class, calling a constructor which either has no parameters or all parameters of which are optional. If there are no or many such constructors, an exception is thrown.
val isSafe = someClass.constructors.singleOrNull {
it.parameters.all(KParameter::isOptional)
} != null
This is similar to how createInstance is implemented to throw the exception.
Is there any way to create an instance of Derived but not call the constructor of Base?
open class Base(p: Int)
class Derived(p: Int) : Base(p)
You actually can do it
import sun.misc.Unsafe
open class Base(p: Int){
init {
println("Base")
}
}
class Derived(p: Int) : Base(p){
init {
println("Derived")
}
}
fun main() {
val unsafe = Unsafe::class.java.getDeclaredField("theUnsafe").apply {
isAccessible = true
}.get(null) as Unsafe
val x = unsafe.allocateInstance(Derived::class.java)
println("X = $x")
}
But don't, this solution is a low-level mechanism that was designed to be used only by the core Java library and not by standard users. You will break the logic of OOP if you use it.
this is not possible. The constructor of the derived class has to call (any) constructor of the base class in order to initialise the content(fields) of the base class.
This is also the same case in Java. Just that the default constructor is called by default (if no parameters are provided in the constructor), but if you have to choose between constructors with parameters, you always have to call them explicitly, because you have to choose which values to pass into the constructor.
You must always call a constructor of a super-class to ensure that the foundation of the class is initialized. But you can work around your issue by providing a no-arg constructor in the base class. Something like this:
open class Base(p: Int?){
val p: Int? = p
constructor(): this(null)
}
class Derived(p: Int) : Base()
The way you handle which constructor of the base class is default and which parameters are nullable, etc. will depend highly on the specific case.
I've bumped into this code and I'm not sure why would anyone do this. Basically the author decided for making the class constructor private so that it cannot be instantiated outside the file, and added a public method to a companion object in the class that creates a new instance of this class. What is the benefit of this approach?
This is what I found:
class Foo private constructor(private val arg1: Any) {
//more code here..
companion object {
fun newFoo(arg1: Any) = Foo(arg1 = arg1)
}
}
Why is it better than this?
class Foo(private val arg1: Any) {
//more code here..
}
There are several benefits to providing a factory method instead of a public constructor, including:
It can do lots of processing before calling the construstor. (This can be important if the superclass constructor takes parameters that need to be calculated.)
It can return cached values instead of new instances where appropriate.
It can return a subclass. (This allows you to make the top class an interface, as noted in another answer.) The exact class can differ between calls, and can even be an anonymous type.
It can have a name (as noted in another answer). This is especially important if you need multiple methods taking the same parameters. (E.g. a Point object which could be constructed from rectangular or polar co-ordinates.) However, a factory method doesn't need a specific name; if you implement the invoke() method in the companion object, you can call it in exactly the same way as a constructor.
It makes it easier to change the implementation of the class without affecting its public interface.
It also has an important drawback:
It can't be used by subclass constructors.
Factory methods seem to be less used in Kotlin than Java, perhaps due to Kotlin's simpler syntax for primary constructors and properties. But they're still worth considering — especially as Kotlin companion objects can inherit.
For much deeper info, see this article, which looks at the recommendation in Effective Java and how it applies to Kotlin.
If you want to change Foo into an interface in the future the code based on the method will keep working, since you can return a concrete class which still implements Foo, unlike the constructor which no longer exists.
An example specific to android is, that Fragments should be constructed with an empty constructed, and any data you'd like to pass through to them should be put in a bundle.
We can create a static/companion function, which takes in the arguments we need for that fragment, and this method would construct the fragment using the empty constructor and pass in the data using a bundle.
There are many useful cases, for example what Kiskae described. Another good one would be to be able to "give your constructors names":
class Foo<S: Any, T: Any> private constructor(private val a: S, private val b: T) {
//more code here...
companion object {
fun <S: Any> createForPurposeX(a: S) = Foo(a = a, b = "Default value")
fun createForPurposeY() = Foo(a = 1, b = 2)
}
}
Call site:
Foo.createForPurposeX("Hey")
Foo.createForPurposeY()
Note: You should use generic types instead of Any.
I'm trying to translate a class from java to kotlin which uses a lot of raw types and accesses the Class of objects.
How can i get this to work:
val item: Any = items[position]
item::class.java // compiler complains about "Unresolved reference: item"
You'll want to call item.javaClass. The reason is that you're not calling on a class literal, you're calling on an actual object instance.