I am unable to mock a Kotlin final class using Mockito 2. I am using Robolectric in addition.
This is my test code:
@RunWith(RobolectricTestRunner.class)
@Config(constants = BuildConfig.class, sdk = 21)
public class Test {
// more mocks
@Mock
MyKotlinLoader kotlinLoader;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
}
}
The test fails when we try to initialise the mocks in the setUp()
method.
In addition, I am using the following gradle dependencies in my code:
testCompile 'org.robolectric:robolectric:3.3.2'
testCompile 'org.robolectric:shadows-multidex:3.3.2'
testCompile 'org.robolectric:shadows-support-v4:3.3.2'
testCompile("org.powermock:powermock-api-mockito2:1.7.0") {
exclude module: 'hamcrest-core'
exclude module: 'objenesis'
}
testCompile 'junit:junit:4.12'
testCompile 'org.mockito:mockito-inline:2.8.9'
All other unit tests pass using this configuration but as soon as I try to mock the Kotlin class it throws the following error:
Mockito cannot mock/spy because: - final class
Please note I am using Mockito version 2 and I am using the inline
dependency which automatically enables the ability to mock final classes.
PowerMock implements its own MockMaker
which leads to incompatibility with Mockito mock-maker-inline, even if PowerMock is just added as a dependency and not used. If two org.mockito.plugins.MockMaker
exist in path then any only one can be used, which one is undetermined.
PowerMock can however delegate calls to another MockMaker, and for then tests are run without PowerMock. Since PowerMock 1.7.0 this can be configured with using the PowerMock Configuration.
The MockMaker can be configured by creating the file org/powermock/extensions/configuration.properties
and setting:
mockito.mock-maker-class=mock-maker-inline
Example of using Mockito mock-maker-inline with PowerMock: https://github.com/powermock/powermock-examples-maven/tree/master/mockito2
Since Mockito 2.1.0 there is a possibility to mock final types, enums, and final methods. It was already mentioned in the comments to the original question.
To do this, you'll need to create a folder (if dont exist) test/resources/mockito-extensions
and add there file with the name org.mockito.plugins.MockMaker
and this line:
mock-maker-inline
Links to documentation and tutorial
Try adding this below dependency to your build.gradle.
testImplementation 'org.mockito:mockito-inline:2.8.47'
Replace with your mockito version instead of 2.8.47. This will help you to avoid using powermock for the issue.
please look into the below link to know how this thing works.
mock-maker-inline
works as is pointed out in other answers. But It's really slow . You can use the all-open
plugin to avoid this problem.
To do so you need:
annotation class Mockable
build.gradle
file:dependencies {
classpath "org.jetbrains.kotlin:kotlin-allopen:$kotlin_version"
}
apply plugin: 'kotlin-allopen'
allOpen {
annotation('com.example.Mockable')
}
@Mockable
class Foo {
fun calculateTheFoo(): Int {
sleep(1_000) // Difficult things here
return 1
}
}
If you want more information you can read my blog post where I explain this with more details: Mocking Kotlin classes with Mockito — the fast way
You may use Powermock for this, for example:
import static org.powermock.api.mockito.PowerMockito.mock;
import static org.powermock.api.mockito.PowerMockito.spy;
import static org.powermock.api.mockito.PowerMockito.when;
@RunWith(RobolectricTestRunner.class)
@Config(constants = BuildConfig.class, sdk = 21)
@PowerMockIgnore({ "org.mockito.*", "org.robolectric.*", "android.*" })
@PrepareForTest({FinalClass1.class, FinalClass2.class})
public class Test {
@Rule
public PowerMockRule rule = new PowerMockRule();
... // your code here
}
Let us program to interfaces, not implementations. You can extract an interface, use it in your code, and mock it. For example, the following will not work:
import com.nhaarman.mockito_kotlin.mock
class MyFinalClass {...}
(snip)
private val MyFinalClass = mock()
So let us extract an interface:
class MyFinalClass : MyInterface {...}
(snip)
private val MyInterface = mock()
Because in kotlin all classes are final by default.
You should also consider adding open
to the class declaration.
Example: open class MyClasss{}
I am unable to mock a Kotlin final class using Mockito 2. I am using Robolectric in addition.
This is my test code:
@RunWith(RobolectricTestRunner.class)
@Config(constants = BuildConfig.class, sdk = 21)
public class Test {
// more mocks
@Mock
MyKotlinLoader kotlinLoader;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
}
}
The test fails when we try to initialise the mocks in the setUp()
method.
In addition, I am using the following gradle dependencies in my code:
testCompile 'org.robolectric:robolectric:3.3.2'
testCompile 'org.robolectric:shadows-multidex:3.3.2'
testCompile 'org.robolectric:shadows-support-v4:3.3.2'
testCompile("org.powermock:powermock-api-mockito2:1.7.0") {
exclude module: 'hamcrest-core'
exclude module: 'objenesis'
}
testCompile 'junit:junit:4.12'
testCompile 'org.mockito:mockito-inline:2.8.9'
All other unit tests pass using this configuration but as soon as I try to mock the Kotlin class it throws the following error:
Mockito cannot mock/spy because : - final class
Please note I am using Mockito version 2 and I am using the inline
dependency which automatically enables the ability to mock final classes.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.