theapache64
theapache64

Reputation: 11744

Kotlin + MockIto + Android Instrumentation Test

I am trying to run an Instrumentation test (androidTest) using Mockito in Android with Kotlin.

but am getting below error while compiling the code

More than one file was found with OS independent path 'mockito-extensions/org.mockito.plugins.MockMaker'

Here's a sample test code to reproduce the issue. Run this test as an Instrumentation test. (androidTest).

MainActivityTest

import androidx.test.ext.junit.runners.AndroidJUnit4
import org.junit.Assert.assertEquals
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mock
import org.mockito.Mockito.`when`
import org.mockito.MockitoAnnotations

class Calculator {
    fun add(x: Int, y: Int): Int {
        return x + y
    }
}

@RunWith(AndroidJUnit4::class)
class MainActivityTest {

    @Mock
    lateinit var calculator: Calculator

    @Before
    fun before() {
        MockitoAnnotations.initMocks(this)
    }

    @Test
    fun test() {
        `when`(calculator.add(10, 10)).thenReturn(20)
        assertEquals(calculator.add(10, 10), 20)
    }
}

app/build.gradle

plugins {
    id 'com.android.application'
    id 'kotlin-android'
    id 'kotlin-android-extensions'
}

android {
    compileSdkVersion 29

    defaultConfig {
        applicationId "com.theapache64.mockitosample"
        minSdkVersion 16
        targetSdkVersion 29
        versionCode 1
        versionName "1.0"

        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
    kotlinOptions {
        jvmTarget = '1.8'
    }

    testOptions {
        unitTests.returnDefaultValues = true
    }
}

dependencies {

    implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
    implementation 'androidx.core:core-ktx:1.2.0'
    implementation 'androidx.appcompat:appcompat:1.1.0'
    implementation 'com.google.android.material:material:1.1.0'
    implementation 'androidx.constraintlayout:constraintlayout:1.1.3'

    testImplementation 'junit:junit:4.13'
    androidTestImplementation 'junit:junit:4.13'
    androidTestImplementation 'androidx.test.ext:junit:1.1.1'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
    androidTestImplementation 'org.mockito:mockito-core:3.3.3'
    androidTestImplementation 'org.mockito:mockito-android:3.3.3'
    androidTestImplementation 'org.mockito:mockito-inline:3.3.3'
}

Isn't it possible to run Android instrumentation test using Kotlin with Mockito ?

NOTE: If you think this is a duplicate question, I've searched all over the internet. There are other issues with similar stack-trace, but my case is different.

Any help would be highly appreciated

Upvotes: 4

Views: 3387

Answers (2)

Mahdi Zareei
Mahdi Zareei

Reputation: 2056

I used these dependencies, they worked for me

androidTestImplementation("androidx.test.ext:junit:1.1.3")
androidTestImplementation("com.linkedin.dexmaker:dexmaker-mockito-inline:2.28.1")
testImplementation("junit:junit:4.13.2")
testImplementation("androidx.test:core:1.4.0")
testImplementation("org.mockito:mockito-android:4.2.0")
testImplementation("org.mockito:mockito-inline:4.2.0")
testImplementation("org.mockito:mockito-core:4.2.0")

Upvotes: 0

Myroslav
Myroslav

Reputation: 1237

I had the same issue and solution for me was this answer https://stackoverflow.com/a/41594789/2286422, - i.e. to use dexmaker library, which has dependency to Mockito.

Remove other Mockito androidTestImplementation dependencies and only add below one (you can find the latest version here):

androidTestImplementation 'com.linkedin.dexmaker:dexmaker-mockito:2.28.1'

Note that this solution will only work on devices with Android P or above (official documentation).

Then in actual test I'm using Mockito in following way:

@RunWith(MockitoJUnitRunner::class) // use Mockito runner to be able to use @Mock annotations
class MockitoTest {

    @Mock
    private lateinit var generalPref: GeneralPreferences

    @Before
    fun setup() {
        // make setup
    }

    @After
    @Throws(IOException::class) {
        // make cleanup
    }

    @Test
    fun testUser() {
        val repo: UserLocalRepository =
            UserLocalRepositoryImpl(generalPref) // generalPref is a mock
        val user = repo.getUser()
        Truth.assertThat(user).isNotNull()
    }
}

Upvotes: 4

Related Questions