Parameterized Test in Kotlin usign mehtod source for nested test class - kotlin

I may use case the class under test has many cases so it is divided into a structure of inner classes. I want to write parameterized test cases to reduce boiler plate and code duplication.
For this I wanted to go with the approach of method source.
Class under test
class UnderTest
{
testThisMethod(a:String,b:String?){
// Do something
externalInterface.call(a?:b)
}
}
Test Case structure
internal class A() {
private val externalService = mockk<ExternalService>
private val test: UnderTest(externalService)
// Some general tests
//---Position Outter
inner class A {
//--- Position A
inner class B {
//--- Position C
#ParameterizedTest
#MethodSource("provideArguments")
fun `with arguments external service create object`(
argument1: String,
argument2: String,
expected: String
) {
// Some code
verify {
externalService.call(expected)
//some more verification
}
}
}
}
}
To provide the argument provider method I tried placing it at positions and got following errors
Position outer: initialization error :Could not find factory method in class
Position A,B: compilation error: companion not allowed here
How can this be achieved?

Try using #TestInstance(TestInstance.Lifecycle.PER_CLASS)
internal class A() {
private val externalService = mockk
private val test: UnderTest(externalService)
// Some general tests
//---Position Outter
inner class A {
//--- Position A
#TestInstance(TestInstance.Lifecycle.PER_CLASS)
inner class B {
//--- Position C
#ParameterizedTest
#MethodSource("provideArguments")
fun `with arguments external service create object`(
argument1: String,
argument2: String,
expected: String
) {
// Some code
verify {
externalService.call(expected)
//some more verification
}
}
}
}
}
Check here for more details

Related

Why is my nested class not accessible? (Kotlin)

I was trying to follow an example from the nested classes documentation: Kotlin docs - Nested and inner classes
So I tried:
fun main(){
var tester = Test()
println(tester.x) // 42
tester.Foo().bar() // compiler error - unresolved reference: Foo!!!
}
class Test {
var x:Int = 42
class Foo {
fun bar() = println("foobar!")
}
}
However, the nested class was not accessible.
I'm obviously missing something really obvious.
If you're not trying to create an inner class, then a nested class should be referenced like so:
fun main() {
var tester = Test()
println(tester.x) // 42
// Static reference
Test.Foo().bar() // foobar!
}
class Test {
var x:Int = 42
inner class Foo {
fun bar() = println("foobar!")
}
}
As #broot said in his comment:
Nested classes are static, so you don't create them from instances

Kotlin inner class can't resolve extension function declared in outer class

Why inner class in Kotlin can't not access extension function declared in outer class as below:
class A{
val a = "as".foo() // LINE 1
class B{
val b = "as".foo() // LINE 2
}
fun String.foo(){}
}
On LINE 1 extension function is resolved but on LINE 2 the function is not resolved. Wonder why there is such limitation?
This is not an inner class, because you didn't use the keyword inner on it. It is merely a nested class. If you're familiar with Java, it's like a static inner class. Since it is not inner, it does not have any implicit reference to the outer class, and cannot make bare calls to members of the outer class since there is no specific instance to use the members of. It can however call members of the outer class on an instance of the outer class, so you could for example do the following:
class A{
val a = "as".foo()
class B{
val b = A().run { "as".foo() }
}
fun String.foo(){}
}
Even though foo is an extension function, it's also a member of A because of where it's declared. Using a scope function that causes a class to be a receiver inside the scope is one way to call one of its member extension functions from another class.
EDIT: Here's an example of one reason you'd want to declare an extension inside a class.
class Sample(val id: Int) {
private val tag = "Sample#$id"
fun String.alsoLogged(): String{
Log.d(tag, this)
return this
}
}
You can use this extension to easily log Strings you're working with inside the class (or when it's the receiver of run or apply). It wouldn't make sense to declare outside the class because it uses the private tag property of that class.
It's because Kotlin compiles your code to
public final class A {
#NotNull
private final Unit a;
#NotNull
public final Unit getA() {
return this.a;
}
public final void foo(#NotNull String $this$foo) {
Intrinsics.checkNotNullParameter($this$foo, "$this$foo");
}
public A() {
this.foo("as");
this.a = Unit.INSTANCE;
}
public static final class B {
public B() {
// You can't access A's foo() method here.
}
}
}

Clean way to access outer class by the implementing delegate class

I was thinking about such case (accessing outer class which uses current class to implement some stuff):
interface Does {
fun doStuff()
}
class ReallyDoes: Does {
var whoShouldReallyDo: Does? = null
override fun doStuff() {
println("Doing stuff instead of $whoShouldReallyDo")
}
}
class MakesOtherDo private constructor(other: Does, hax: Int = 42): Does by other {
constructor(other: ReallyDoes): this(other.also { it.whoShouldReallyDo = this }, 42)
}
fun main(args: Array<String>) {
val worker = ReallyDoes()
val boss = MakesOtherDo(other = worker)
boss.doStuff()
}
Expected output:
Doing stuff instead of MakesOtherDo#28a418fc
But can't do that, because of error:
Error:(15, 79) Cannot access '' before superclass constructor
has been called
Which targets this statement: other.also { it.whoShouldReallyDo = this }
How can I (if at all) fix above implementation?
The reason for the error is other.also { ... = this } expression accesses this of type MakeOtherDo and is also used as argument to MakeOtherDo constructor. Hence, this will be accessed as part of MakeOtherDo (unary) constructor before this has been initialized as an instance of Does (super)class.
Since the assignment does not affect the initialization of the super class, you can executed it in the constructor of MakesOtherDo after the super class has been initialized.
class MakesOtherDo private constructor(other: Does, hax: Int = 42): Does by other {
constructor(other: ReallyDoes): this(other, 42) {
other.also { it.whoShouldReallyDo = this }
}
}
It took me a few minutes to decipher what you were doing above, and really the problem has nothing to do with delegates. You can simplify it down to this:
class Wrapper(var any: Any? = null)
class Test(val wrapper: Wrapper) {
constructor(): this(Wrapper(this)) // Cannot access "<this>" before superclass constructor has been called
}
The concept of "this" doesn't exist yet when we're still generating arguments for its constructor. You just need to move the assignment into the block of the constructor, which is code that's run after this becomes available:
class Test(val wrapper: Wrapper) {
constructor(): this(Wrapper()){
wrapper.any = this
}
}
Or in the case of your example:
constructor(other: ReallyDoes): this(other, 42){
other.whoShouldReallyDo = this
}

Hiding base class constructor parameters in Kotlin

I am trying to understand how to hide a base constructor parameter in a subclass in kotlin. How do you put a facade over a base constructor? This doesn't work:
import com.android.volley.Request
import com.android.volley.Response
class MyCustomRequest(url: String)
: Request<String>(Request.Method.POST, url, hiddenListener) {
private fun hiddenListener() = Response.ErrorListener {
/* super secret listener */
}
...
}
I think I understand the problem:
During construction of a new instance of a derived class, the base
class initialization is done as the first step (preceded only by
evaluation of the arguments for the base class constructor) and thus
happens before the initialization logic of the derived class is run.
I'm trying to solve this problem for Volley, where I need my custom request to be be a Request so that it can be passed into a RequestQueue. It would be easier of RequestQueue took in some kind of interface but since it doesn't I have to subclass. There are other ways I can hide these complexities from the caller, but this limitation has come up for me other times in Kotlin and I'm not sure how to solve it.
I am not familiar with volley but I tried to come up with an example that should give you some insight how to solve your problem. What you can do is use a companion object:
interface MyListener {
fun handleEvent()
}
open class Base<T>(anything: Any, val listener: MyListener) { // this would be your Request class
fun onSomeEvent() {
listener.handleEvent()
}
}
class Derived(anything: Any) : Base<Any>(anything, hiddenListener) { // this would be your MyCustomRequest class
private companion object {
private val hiddenListener = object : MyListener {
override fun handleEvent() {
// do secret stuff here
}
}
}
}
So if you apply this to your problem, the result should look something like this:
class MyCustomRequest(url: String)
: Request<String>(Request.Method.POST, url, hiddenListener) {
private companion object {
private val hiddenListener = Response.ErrorListener {
/* super secret listener */
}
}
...
}
A different way would be to use a decorator, create your Request withing that decorator and just delegate the calls to it:
class Decorator(anything: Any) {
private var inner: Base<Any>
private val hiddenListener: MyListener = object : MyListener {
override fun handleEvent() { }
}
init {
inner = Base(anything, hiddenListener)
}
}
And once again for your example that would look like this:
class MyCustomRequest(url: String) {
private var inner: Request<String>
private val hiddenListener = Response.ErrorListener {
/* super secret listener */
}
init {
inner = Request<String>(Request.Method.POST, url, hiddenListener)
}
...
}

Inner class create fail in Kotlin

This code sample cannot be compiled and shows an internal error.
open class TestClass {
open inner class Back {
open fun dd() { }
}
}
class Manager: TestClass() {
private val test = object : Back() {
override fun dd() { }
}
}
Cause:
Error generating constructors of class null with kind IMPLEMENTATION
What does it mean?
The example provided refers to KT-11833 and now compiles. Checked it with Kotlin version 1.1.0-beta-22.