i have a class under Test which is marked as "interal"
internal class UnderTest{
fun methodToTest(){}
}
In my JUnit Test i want test UnderTest
import com.nhaarman.mockito_kotlin.mock
class SimpleTest{
val mock = mock<UnderTest>()
#Test
fun test(){
assertThat(....)
}
}
And here it gets a bit strange, as Android Studio complains first that UnderTest is not visible "public property exposes it's private type". Thats because UnderTest is marked as internal.
I changed the Test itself to be internal, which results that the compiler is happy again:
import com.nhaarman.mockito_kotlin.mock
internal class SimpleTest{
val mock = mock<UnderTest>()
#Test
fun test(){
assertThat(....)
}
}
Running this test results in an mockito exception like in the old mockito versions
Cannot mock/spy class com.name.UnderTest
Mockito cannot mock/spy because :
- final class
I want to write Unit Test for those internal classes, but how without removing the internal modifier from UnderTest class ?
Thanks
The issue is not that the class is internal (it's equivalent to public within the same module) but rather that it's final. By default all classes in Kotlin are final unless you mark them with open.
So if you want to mock your class you should mark it as internal open class Xyz.
Note that there's a Maven/Gradle plugin that automatically opens all classes for you: all-open plugin.
For example, given the following Kotlin class:
internal open class Foo
The following unit test passes:
class FooTest {
#Test
fun shouldPass() {
Mockito.mock(Foo::class.java)
}
}
Related
I'd like to set an order over the Test Class.
#RunWith(AndroidJUnit4::class)
#FixMethodOrder(MethodSorters.NAME_ASCENDING)
class ATest {
#Test
fun test0000()
#Test
fun test0001()
}
#RunWith(AndroidJUnit4::class)
#FixMethodOrder(MethodSorters.NAME_ASCENDING)
class BTest {
#Test
fun test0002()
#Test
fun test0003()
}
I'd like to test ATest.test0000 -> ATest.test0001 -> BTest.test0002 -> BTest.test0003
Because ATest class must be tested before B Test.
How can I do that? Is it possible?
Firstly, I would recommend you to not have any dependencies in Tests.
i.e. Test A class and Test B class should run independently from each other.
This really helps when your application grows.
There should not be a condition that one test should run before another.
Only in a rare / genuine scenario we should have such dependency on sequence.
Because if you design your test with sequence related dependency then it will be difficult for you to maintain your test cases and it will get difficult when you follow Test Driven Development(TDD).
For above case, please try using SuiteClasses.
The SuiteClasses annotation specifies the Suite runner which test classes to include in this suite and in which order.
Please refer to the sample provided by Junit Team HERE
I need a context in some unit test classes. I'm getting errors from 3rd SDKs when I try to provide an application class. So, I want to provide an empty application class for the unit tests.
#RunWith(RobolectricTestRunner::class)
class SampleTest {
private val context: Context = ApplicationProvider.getApplicationContext()
I already looked at the source code, the only thing i'm curious about to know why both the versions are exist one should had to be deprecated, no ?
Today I was writing unit tests for one of my viewModel class, in the repository class I have used android.util.ArrayMap. I did initialize ArrayMap with fake value but while debugging found that arrayMap size is always zero.
arrayMap["key1"] = someValue
arrayMap["key2"] = someValue
arrayMap["key3"] = someValue
But when I change it to androidx.collection.ArrayMap it works fine. But the problem is I already used android.util.ArrayMap in my repository and viewModel class and at this moment I don't want to convert that to androidx.collection.ArrayMap.
Here is the test class.
import android.util.ArrayMap
//import androidx.collection.ArrayMap // switching to this works fine
import org.junit.*
import org.junit.Assert.assertNotNull
import org.junit.runners.MethodSorters
#FixMethodOrder(MethodSorters.NAME_ASCENDING)
class AudioViewModelTest {
private lateinit var audioMap: ArrayMap<Int, AudioItem>
#Before
fun setUp() {
audioMap = ArrayMap()
val audioItem = AudioItem()
audioMap[1] = audioItem
audioMap[2] = audioItem
audioMap[3] = audioItem
assertNotNull(audioMap[1])// this is failing
}
#Test
fun testAudioMap() {
assertNotNull(audioMap[1])// this is failing
}
}
Can someone please explain why android.util.ArrayMap always have size as ZERO even if I add some element into that.
You cannot use Android platform classes in your local tests. In your local test, you have just mock of the android.util.ArrayMap class. That's why it's size is always 0. You have to use instrumented tests or use androidx.collection.ArrayMap
Im writting Unit Tests for my app and I've found a "speed bump" while writting them. While testing subclasses of AndroidViewModel im missing the Application parameter for its initialization. I've already read this question that uses Robolectric.
This is what I already tried so far:
Using Robolectric as the question describes. As far as I understand, Robolectric can use your custom Application class for testing, the thing is im not using a custom application class as I dont need it. (the app is not that complex).
Using mockito. Mockito throws an exception saying that the Context class cannot be mocked.
Using the InstrumentationRegistry. I moved the test classes from the test folder to the androidTest folder, giving me access to the androidTestImplementation dependencies, I tried using the InstrumentationRegistry.getContext() and parse it to Application, of course this didn't worked, throwing a cast exception. I felt so dumb trying this but again, it was worth the shot.
I just want to instanciate my AndroidViewModel classes so I can call their public methods, but the Application parameter is needed. What can I do for this?
fun someTest() {
val testViewModel = MyViewModelThatExtendsFromAndroidViewModel(**missing application parameter**)
testViewModel.foo() // The code never reaches here as the testViewModel cant be initializated
}
I had the same issue, and found two solutions.
You can use Robolectric in a Unit Test, inside test directory, and choose the platform Application class.
#RunWith(RobolectricTestRunner::class)
#Config(application = Application::class)
class ViewModelTest {
#Test
#Throws(Exception::class)
fun someTest() {
val application = RuntimeEnvironment.application
val testViewModel = MyViewModelThatExtendsFromAndroidViewModel(application)
testViewModel.foo()
}
}
Or you can use an InstrumentationTest inside androidTest directory, and cast the InstrumentationRegistry.getTargetContext().applicationContext to Application:
#RunWith(AndroidJUnit4::class)
class ViewModelTest {
#Test
#Throws(Exception::class)
fun someTest() {
val application = ApplicationProvider.getApplicationContext() as Application
val testViewModel = MyViewModelThatExtendsFromAndroidViewModel(application)
testViewModel.foo()
}
}
Hope it helped!
I want to combine both Robolectric and Cucumber (JVM).
Currently I have two classes ActivityStepdefs where two step definitions for activity management are defined.
My second class is RoActivity Where for example an activity is created from it's class name, and where Robolectric will be used.
When I run RoActivityTest using RobolectricTestRunner the test in this class passes, but when I run RunCukesTest (class for running features as junit test) the code from RoActivity is not running as part of Robolectric, i.e. RunCukesTest search for features on my project and match it with a method inside ActivityStepdefs and finally this class will call a method from RoActivity
Is possible to run test with both junit both* runners?
I'm not sure but perhaps it's possible to do something like powermock, using junit rules.
In that case for which one should I have to define the rule?
*Cucumber and Robolectric
My small 5 cents.
Cucumber is mostly used for acceptance tests (correct me if you use it for unit testing) and Robolectric is mostly used for unit testing.
As for me, it is overkill to write cucumber during TDD. And Robolectric is still not android and I would run acceptance tests on real device or at least emulator.
I'am facing the same problem, after some google work, I got a solution:
#RunWith(ParameterizedRobolectricTestRunner::class)
#CucumberOptions( features = ["src/test/features/test.feature","src/test/features/others.feature"], plugin = ["pretty"])
class RunFeatures(val index: Int, val name:String) {
companion object {
#Parameters(name = "{1}")
#JvmStatic
fun features(): Collection<Array<Any>> {
val runner = Cucumber(RunFeatures::class.java)
Cucumber()
val children = runner.children
return children.mapIndexed{index, feature ->
arrayOf(index,feature.name)
}
}
}
#Test
fun runTest() {
val core = JUnitCore()
val feature = Cucumber(RunFeatures::class.java).children[index]!!
core.addListener(object: RunListener() {
override fun testFailure(failure: Failure?) {
super.testFailure(failure)
fail("$name failed:\n"+failure?.exception)
}
})
val runner = Request.runner(feature)
core.run(runner)
}
}
but seems not an pretty solution for me, can somebody help me out these problem:
must explicitly list all feature file path. but cannot use pattern such as *.feature
when failed cannot know which step failed.
parameter can only pass primitive type data,
I've get into cucumber source , but seems CucumberOptions inline Cucumber , I cannot pass it programmatically but can only use annotation .