Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Can't mock Java's private methods that use Collection<T> and defined in not final class #429

Open
3 tasks done
tko3 opened this issue Apr 20, 2020 · 0 comments
Open
3 tasks done

Comments

@tko3
Copy link

tko3 commented Apr 20, 2020

Prerequisites

Please answer the following questions for yourself before submitting an issue.

  • I am running the latest version
  • I checked the documentation and found no answer
  • I checked to make sure that this issue has not already been filed

Expected Behavior

Can mock any private methods.

Current Behavior

I can't mock private methods that use Java's Collection<T> in not final class.

Failure Information (for bugs)

Please see minimal code and StackTrace.

Context

Please provide any relevant information about your setup. This is important in case the issue is not reproducible except for under certain conditions.

  • MockK version: 1.10.0
  • OS: macOS Catalina 10.15.4
  • Kotlin version: 1.3.10
  • JDK version: 1.8.0_212-release(bundling in Android Studio 3.6)
  • JUnit version: 4.12
  • Type of test: android instrumented test

Failure Logs

Please include any relevant log snippets or files here.

Stack trace

io.mockk.MockKException: can't find function privateMethod(1243820262, java.lang.Object_2b8831a_Proxy@9a7eeaa) for dynamic call
at io.mockk.InternalPlatformDsl.dynamicCall(InternalPlatformDsl.kt:122)
at io.mockk.MockKMatcherScope$DynamicCallLong.withArguments(API.kt:1979)
at com.example.testapplication.SampleClassTest$testSampleMethod$1.invoke(SampleClassTest.kt:19)
at com.example.testapplication.SampleClassTest$testSampleMethod$1.invoke(SampleClassTest.kt:12)
at io.mockk.impl.eval.RecordedBlockEvaluator$record$block$1.invoke(RecordedBlockEvaluator.kt:24)
at io.mockk.impl.eval.RecordedBlockEvaluator$enhanceWithNPERethrow$1.invoke(RecordedBlockEvaluator.kt:74)
at io.mockk.impl.recording.JvmAutoHinter.autoHint(JvmAutoHinter.kt:23)
at io.mockk.impl.eval.RecordedBlockEvaluator.record(RecordedBlockEvaluator.kt:36)
at io.mockk.impl.eval.EveryBlockEvaluator.every(EveryBlockEvaluator.kt:30)
at io.mockk.MockKDsl.internalEvery(API.kt:92)
at io.mockk.MockKKt.every(MockK.kt:98)
at com.example.testapplication.SampleClassTest.testSampleMethod(SampleClassTest.kt:19)
at java.lang.reflect.Method.invoke(Native Method)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at androidx.test.runner.AndroidJUnit4.run(AndroidJUnit4.java:104)
at org.junit.runners.Suite.runChild(Suite.java:128)
at org.junit.runners.Suite.runChild(Suite.java:27)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at org.junit.runner.JUnitCore.run(JUnitCore.java:115)
at androidx.test.internal.runner.TestExecutor.execute(TestExecutor.java:56)
at androidx.test.runner.AndroidJUnitRunner.onStart(AndroidJUnitRunner.java:392)
at android.app.Instrumentation$InstrumentationThread.run(Instrumentation.java:2145)

Minimal reproducible code (the gist of this issue)

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])

    implementation 'androidx.appcompat:appcompat:1.1.0'
    implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'androidx.test.ext:junit:1.1.1'

    implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.3.61"
    androidTestImplementation 'androidx.test:core:1.0.0'
    androidTestImplementation 'androidx.test:runner:1.1.0'
    androidTestImplementation 'androidx.test:rules:1.2.0'
    androidTestImplementation 'io.mockk:mockk:1.10.0'
    androidTestImplementation 'io.mockk:mockk-android:1.10.0'
    androidTestImplementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.2'
    androidTestImplementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.2'
}
package com.example.testapplication;

import android.content.Context;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;

class SampleClass {

  Collection<String> sampleMethod(int num) {
    List<Integer> list = new ArrayList<>();
    list.add(2);
    list.add(5);
    return this.privateMethod(num, list);
  }

  Collection<String> sampleMethod2(int num) {
    List<Integer> list = new ArrayList<>();
    list.add(2);
    list.add(5);
    return innerMethod(num, list);
  }

  private Collection<String> privateMethod(int num, List<Integer> list) {
    Collection<String> collection = new HashSet<String>();
    for (int i = 0; i < list.size(); i++) {
      collection.add(String.valueOf(list.get(i) + num));
    }
    return collection;
  }

  Collection<String> innerMethod(int num, List<Integer> list) {
    Collection<String> collection = new HashSet<String>();
    for (int i = 0; i < list.size(); i++) {
      collection.add(String.valueOf(list.get(i) + num));
    }
    return collection;
  }
}
package com.example.testapplication;

import android.content.Context;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;

public final class SampleFinalClass {


  Collection<String> sampleMethod(int num) {
    List<Integer> list = new ArrayList<>();
    list.add(2);
    list.add(5);
    return this.privateMethod(num, list);
  }

  Collection<String> sampleMethod2(int num) {
    List<Integer> list = new ArrayList<>();
    list.add(2);
    list.add(5);
    return innerMethod(num, list);
  }

  private Collection<String> privateMethod(int num, List<Integer> list) {
    Collection<String> collection = new HashSet<String>();
    for (int i = 0; i < list.size(); i++) {
      collection.add(String.valueOf(list.get(i) + num));
    }
    return collection;
  }

  Collection<String> innerMethod(int num, List<Integer> list) {
    Collection<String> collection = new HashSet<String>();
    for (int i = 0; i < list.size(); i++) {
      collection.add(String.valueOf(list.get(i) + num));
    }
    return collection;
  }
}
package com.example.testapplication

import androidx.test.runner.AndroidJUnit4
import io.mockk.every
import io.mockk.spyk
import junit.framework.Assert.assertEquals
import junit.framework.Assert.assertTrue
import org.junit.Test
import org.junit.runner.RunWith

@RunWith(AndroidJUnit4::class)
class SampleClassTest {

  @Test
  fun testSampleMethod() {
    val mock = spyk<SampleClass>(recordPrivateCalls = true)

    // io.mockk.MockKException: can't find function privateMethod
    every { mock invoke "privateMethod" withArguments listOf(any<Int>(), any<List<Int>>()) } returns listOf("4", "10")

    val result = mock.sampleMethod(3)
    assertEquals(2, result.size)
    assertTrue(result.contains("4"))
    assertTrue(result.contains("10"))
  }

  @Test
  fun testSampleMethod2() {
    val mock = spyk<SampleClass>(recordPrivateCalls = true)

    // Success
    every { mock.innerMethod(any<Int>(), any<List<Int>>()) } returns listOf("4", "10")

    val result = mock.sampleMethod2(3)
    assertEquals(2, result.size)
    assertTrue(result.contains("4"))
    assertTrue(result.contains("10"))
  }
}
package com.example.testapplication

import androidx.test.runner.AndroidJUnit4
import io.mockk.every
import io.mockk.spyk
import junit.framework.Assert
import org.junit.Test
import org.junit.runner.RunWith

@RunWith(AndroidJUnit4::class)
class SampleFinalClassTest {

  @Test
  fun testSampleMethod() {
    val mock = spyk<SampleFinalClass>(recordPrivateCalls = true)

    // Success
    every { mock invoke "privateMethod" withArguments listOf(any<Int>(), any<List<Int>>()) } returns listOf("4", "10")

    val result = mock.sampleMethod(3)
    Assert.assertEquals(2, result.size)
    Assert.assertTrue(result.contains("4"))
    Assert.assertTrue(result.contains("10"))
  }

  @Test
  fun testSampleMethod2() {
    val mock = spyk<SampleFinalClass>(recordPrivateCalls = true)

    // Success
    every { mock.innerMethod(any<Int>(), any<List<Int>>()) } returns listOf("4", "10")

    val result = mock.sampleMethod2(3)
    Assert.assertEquals(2, result.size)
    Assert.assertTrue(result.contains("4"))
    Assert.assertTrue(result.contains("10"))
  }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants