toothpick
toothpick copied to clipboard
Tests with TP - Mockk
Hello !
I didn't find a solution in the others issues or in the samples.
I think this case can help the others developpers.
I'm trying to do some simple tests on my useCase and i use Mockk and jUnit.
I have an error in the injection of my object geocoder, this is the stacktrace of my error:
"C:\Program Files\Android\Android Studio\jre\bin\java.exe" -ea -Didea.test.cyclic.buffer.size=1048576 "-javaagent:C:\Program Files\Android\Android Studio\lib\idea_rt.jar=54730:C:\Program Files\Android\Android Studio\bin" -Dfile.encoding=UTF-8 -classpath "C:\Program Files\Android\Android Studio\lib\idea_rt.jar;C:\Program Files\Android\Android Studio\plugins\junit\lib\junit-rt.jar;C:\Program Files\Android\Android Studio\plugins\junit\lib\junit5-rt.jar;C:\Users\cgizard\AppData\Local\Android\Sdk\platforms\android-28\data\res;C:\Users\cgizard\Documents\android\TP\tp-hands-on\app\build\intermediates\javac\debug\compileDebugJavaWithJavac\classes;C:\Users\cgizard\Documents\android\TP\tp-hands-on\app\build\tmp\kotlin-classes\debugUnitTest;C:\Users\cgizard\Documents\android\TP\tp-hands-on\app\build\tmp\kapt3\classes\debugUnitTest;C:\Users\cgizard\Documents\android\TP\tp-hands-on\app\build\tmp\kotlin-classes\debug;C:\Users\cgizard\Documents\android\TP\tp-hands-on\app\build\tmp\kapt3\classes\debug;C:\Users\cgizard\Documents\android\TP\tp-hands-on\app\build\generated\res\resValues\debug;C:\Users\cgizard\.gradle\caches\transforms-2\files-2.1\c6795502c19e8a5d6eabaa9cdbd66997\res;C:\Users\cgizard\.gradle\caches\transforms-2\files-2.1\c6795502c19e8a5d6eabaa9cdbd66997\jars\classes.jar;C:\Users\cgizard\.gradle\caches\modules-2\files-2.1\io.mockk\mockk-common\1.9.3\7f2d6bc3390a76edeba34947e0de6d2314645f25\mockk-common-1.9.3.jar;C:\Users\cgizard\.gradle\caches\modules-2\files-2.1\org.jetbrains.kotlin\kotlin-stdlib-common\1.3.21\f30e4a9897913e53d778f564110bafa1fef46643\kotlin-stdlib-common-1.3.21.jar;C:\Users\cgizard\.gradle\caches\transforms-2\files-2.1\8ca8272201e593e52e9c3f9fb373ec63\jars\classes.jar;C:\Users\cgizard\.gradle\caches\transforms-2\files-2.1\d70717a9c47ffb8f42325f3fa33c6ca2\jars\classes.jar;C:\Users\cgizard\.gradle\caches\transforms-2\files-2.1\865f91dd4d720ab709673f330b189b38\jars\classes.jar;C:\Users\cgizard\.gradle\caches\transforms-2\files-2.1\ed34f65b24a5f2d904fafe9658e3a656\jars\classes.jar;C:\Users\cgizard\.gradle\caches\transforms-2\files-2.1\ed34f65b24a5f2d904fafe9658e3a656\res;C:\Users\cgizard\.gradle\caches\transforms-2\files-2.1\b109d70fffa07d2a87e27e2745d9a48f\res;C:\Users\cgizard\.gradle\caches\transforms-2\files-2.1\b109d70fffa07d2a87e27e2745d9a48f\jars\classes.jar;C:\Users\cgizard\.gradle\caches\modules-2\files-2.1\org.objenesis\objenesis\3.0.1\11cfac598df9dc48bb9ed9357ed04212694b7808\objenesis-3.0.1.jar;C:\Users\cgizard\.gradle\caches\modules-2\files-2.1\com.github.stephanenicolas.toothpick\toothpick\2.1.0\b64a81c97ae4114edf642cf6682a48e5f9ea4f60\toothpick-2.1.0.jar;C:\Users\cgizard\.gradle\caches\transforms-2\files-2.1\b59126231dffdecbf434e4e92ad501cf\jars\classes.jar;C:\Users\cgizard\.gradle\caches\transforms-2\files-2.1\18d32e120f53d5d4b2d0a211db428579\jars\classes.jar;C:\Users\cgizard\.gradle\caches\transforms-2\files-2.1\e651c45e32b929d002b4f3d9eba6cac9\jars\classes.jar;C:\Users\cgizard\.gradle\caches\transforms-2\files-2.1\77409a87a50559dc4ac8ea7c93176285\jars\classes.jar;C:\Users\cgizard\.gradle\caches\transforms-2\files-2.1\8794ace6b2e185e1e5931bee308a883d\jars\classes.jar;C:\Users\cgizard\.gradle\caches\transforms-2\files-2.1\1ff7fdbf7685aa8ab89f930f5f504053\jars\classes.jar;C:\Users\cgizard\.gradle\caches\modules-2\files-2.1\io.mockk\mockk\1.9.3\d26e5a4a7fd4ecb5635b28a0b70960ab0b20556d\mockk-1.9.3.jar;C:\Users\cgizard\.gradle\caches\transforms-2\files-2.1\d49a08e6720db72b176b6b86a81b8c8b\jars\classes.jar;C:\Users\cgizard\.gradle\caches\modules-2\files-2.1\io.mockk\mockk-dsl-jvm\1.9.3\63de994ae1f30b06395325258d2e5683a8bdd525\mockk-dsl-jvm-1.9.3.jar;C:\Users\cgizard\.gradle\caches\transforms-2\files-2.1\3b8b7528a9c480055b0bc8a6c4ce43c3\jars\classes.jar;C:\Users\cgizard\.gradle\caches\transforms-2\files-2.1\f297cf209a39d8e848f12e919706ecd2\jars\classes.jar;C:\Users\cgizard\.gradle\caches\transforms-2\files-2.1\8f939a3fffca1e316e412afe4fe4d171\jars\classes.jar;C:\Users\cgizard\.gradle\caches\transforms-2\files-2.1\019635dc309cb5332d6b155403b9742a\jars\classes.jar;C:\Users\cgizard\.gradle\caches\transforms-2\files-2.1\55106300991dd47fd137f6020ad54dbf\jars\classes.jar;C:\Users\cgizard\.gradle\caches\transforms-2\files-2.1\88e4678c43eceaa0a35b933e12030f52\jars\classes.jar;C:\Users\cgizard\.gradle\caches\modules-2\files-2.1\com.github.stephanenicolas.toothpick\toothpick-testing\2.1.0\6f914c89fad3a21a462ddbabcd6b095413a9eef\toothpick-testing-2.1.0.jar;C:\Users\cgizard\.gradle\caches\modules-2\files-2.1\javax.inject\javax.inject\1\6975da39a7040257bd51d21a231b76c915872d38\javax.inject-1.jar;C:\Users\cgizard\.gradle\caches\transforms-2\files-2.1\0c89adce95726f4a2de6ecda09361028\jars\classes.jar;C:\Users\cgizard\.gradle\caches\transforms-2\files-2.1\5ae993c5672e29747357921022065e94\jars\classes.jar;C:\Users\cgizard\.gradle\caches\modules-2\files-2.1\com.squareup.retrofit2\retrofit\2.3.0\bcacde6a8ccedcc56c127403d26b76072fe6214d\retrofit-2.3.0.jar;C:\Users\cgizard\.gradle\caches\transforms-2\files-2.1\6a0900a69f16da6bc985ac53699576d4\res;C:\Users\cgizard\.gradle\caches\transforms-2\files-2.1\6a0900a69f16da6bc985ac53699576d4\jars\classes.jar;C:\Users\cgizard\.gradle\caches\transforms-2\files-2.1\ce28f4e7a09920aeb4fdaf1e1a13dae6\jars\classes.jar;C:\Users\cgizard\.gradle\caches\modules-2\files-2.1\com.squareup.okhttp3\okhttp\3.8.0\5a11f020cce2d11eb71ba916700600e18c4547e7\okhttp-3.8.0.jar;C:\Users\cgizard\.gradle\caches\transforms-2\files-2.1\aa8af142f22b4c172172be6c6e546968\res;C:\Users\cgizard\.gradle\caches\transforms-2\files-2.1\aa8af142f22b4c172172be6c6e546968\jars\classes.jar;C:\Users\cgizard\.gradle\caches\transforms-2\files-2.1\b92615a755bc2258b620e1f8d5713a4c\jars\classes.jar;C:\Users\cgizard\.gradle\caches\transforms-2\files-2.1\34a3c90db54e28834292217e153b69ab\jars\classes.jar;C:\Users\cgizard\.gradle\caches\modules-2\files-2.1\org.jetbrains.kotlin\kotlin-stdlib\1.3.21\4bcc2012b84840e19e1e28074284cac908be0295\kotlin-stdlib-1.3.21.jar;C:\Users\cgizard\.gradle\caches\transforms-2\files-2.1\78254233f2a4c90a6ee5177e9321dc5b\jars\classes.jar;C:\Users\cgizard\.gradle\caches\modules-2\files-2.1\org.jetbrains.kotlin\kotlin-stdlib-jdk7\1.3.21\d207ce2c9bcf17dc8e51bab4dbfdac4d013e7138\kotlin-stdlib-jdk7-1.3.21.jar;C:\Users\cgizard\.gradle\caches\transforms-2\files-2.1\2a071358abfb82c91f1ff48fe35181b2\jars\classes.jar;C:\Users\cgizard\.gradle\caches\transforms-2\files-2.1\7e80f8dacd5ecd74c1e36fb960219d2c\jars\classes.jar;C:\Users\cgizard\.gradle\caches\transforms-2\files-2.1\c64e06ab3d5d05b81846497ed544c269\jars\classes.jar;C:\Users\cgizard\.gradle\caches\transforms-2\files-2.1\45b75ecf8e521d64018454f6e9db0f0d\jars\classes.jar;C:\Users\cgizard\.gradle\caches\transforms-2\files-2.1\c60f15e29098cfd94b790bbccd36bba9\jars\classes.jar;C:\Users\cgizard\.gradle\caches\transforms-2\files-2.1\c60f15e29098cfd94b790bbccd36bba9\res;C:\Users\cgizard\.gradle\caches\modules-2\files-2.1\com.squareup.okio\okio\1.13.0\a9283170b7305c8d92d25aff02a6ab7e45d06cbe\okio-1.13.0.jar;C:\Users\cgizard\.gradle\caches\transforms-2\files-2.1\3a0a92403d15aea2b2aefd4f4d8ae956\jars\classes.jar;C:\Users\cgizard\.gradle\caches\transforms-2\files-2.1\3a0a92403d15aea2b2aefd4f4d8ae956\res;C:\Users\cgizard\.gradle\caches\modules-2\files-2.1\org.reactivestreams\reactive-streams\1.0.2\323964c36556eb0e6209f65c1cef72b53b461ab8\reactive-streams-1.0.2.jar;C:\Users\cgizard\.gradle\caches\modules-2\files-2.1\io.reactivex.rxjava2\rxjava\2.2.7\394ee6d9e141acb9fbf9daf228fd8cd789eaa49a\rxjava-2.2.7.jar;C:\Users\cgizard\.gradle\caches\transforms-2\files-2.1\ad05011a2d5ce5783c8e5daed5d668e2\jars\classes.jar;C:\Users\cgizard\.gradle\caches\modules-2\files-2.1\org.jetbrains.kotlin\kotlin-reflect\1.3.0\6fd129fd9ba8581f2cb9c58bfd431dda4ee0457e\kotlin-reflect-1.3.0.jar;C:\Users\cgizard\.gradle\caches\modules-2\files-2.1\com.squareup.retrofit2\converter-moshi\2.3.0\6ad87c2038269d2574fcd90765ce15c74d6bb993\converter-moshi-2.3.0.jar;C:\Users\cgizard\.gradle\caches\transforms-2\files-2.1\f0dd84b927ccee47e41fc467d6ae3d80\res;C:\Users\cgizard\.gradle\caches\transforms-2\files-2.1\f0dd84b927ccee47e41fc467d6ae3d80\jars\classes.jar;C:\Users\cgizard\.gradle\caches\transforms-2\files-2.1\7c7fdc87993bbead6e1a943997fb89d2\jars\classes.jar;C:\Users\cgizard\.gradle\caches\modules-2\files-2.1\androidx.annotation\annotation\1.0.1\2dfd8f6b2a8fc466a1ae4e329fb79cd580f6393f\annotation-1.0.1.jar;C:\Users\cgizard\.gradle\caches\modules-2\files-2.1\io.mockk\mockk-dsl\1.9.3\4f158b4ed161bc4373356733088e09491ecd13da\mockk-dsl-1.9.3.jar;C:\Users\cgizard\.gradle\caches\modules-2\files-2.1\io.mockk\mockk-agent-jvm\1.9.3\d6f7b4d893caf1cda2bb28ee637b247ced5d5eab\mockk-agent-jvm-1.9.3.jar;C:\Users\cgizard\.gradle\caches\modules-2\files-2.1\androidx.lifecycle\lifecycle-common\2.0.0\e070ffae07452331bc5684734fce6831d531785c\lifecycle-common-2.0.0.jar;C:\Users\cgizard\.gradle\caches\transforms-2\files-2.1\12ff022c1706ebb82f05509eb6f947ac\jars\classes.jar;C:\Users\cgizard\.gradle\caches\transforms-2\files-2.1\4c4e131b467b4bb3c6fa9b7ccfa245e5\jars\classes.jar;C:\Users\cgizard\.gradle\caches\transforms-2\files-2.1\ad6da781350574fb8d2326ced99875d5\jars\classes.jar;C:\Users\cgizard\.gradle\caches\modules-2\files-2.1\androidx.constraintlayout\constraintlayout-solver\1.1.3\54abe9ffb22cc9019b0b6fcc10f185cc4e67b34e\constraintlayout-solver-1.1.3.jar;C:\Users\cgizard\.gradle\caches\modules-2\files-2.1\io.mockk\mockk-agent-common\1.9.3\50f32c350cb9018a62e6de2bed710acf675f887b\mockk-agent-common-1.9.3.jar;C:\Users\cgizard\.gradle\caches\modules-2\files-2.1\org.jetbrains\annotations\16.0.1\c1a6655cebcac68e63e4c24d23f573035032eb2a\annotations-16.0.1.jar;C:\Users\cgizard\.gradle\caches\transforms-2\files-2.1\c829d1c7b59b8404cddb78216b671cec\jars\classes.jar;C:\Users\cgizard\.gradle\caches\transforms-2\files-2.1\202469d5ef282e44cdaae0fb89545d95\jars\classes.jar;C:\Users\cgizard\.gradle\caches\modules-2\files-2.1\com.github.stephanenicolas.toothpick\toothpick-runtime\2.1.0\e4456493ef995a4e7c4a541a64106a5b4c78a685\toothpick-runtime-2.1.0.jar;C:\Users\cgizard\.gradle\caches\modules-2\files-2.1\androidx.arch.core\core-common\2.0.0\bb21b9a11761451b51624ac428d1f1bb5deeac38\core-common-2.0.0.jar;C:\Users\cgizard\.gradle\caches\transforms-2\files-2.1\ee64b893024ba1ab76bfb22946847ae2\res;C:\Users\cgizard\.gradle\caches\transforms-2\files-2.1\ee64b893024ba1ab76bfb22946847ae2\jars\classes.jar;C:\Users\cgizard\.gradle\caches\transforms-2\files-2.1\933458fe4cba7ca8ce1be45a5976cafc\jars\classes.jar;C:\Users\cgizard\.gradle\caches\transforms-2\files-2.1\933458fe4cba7ca8ce1be45a5976cafc\res;C:\Users\cgizard\.gradle\caches\modules-2\files-2.1\junit\junit\4.12\2973d150c0dc1fefe998f834810d68f278ea58ec\junit-4.12.jar;C:\Users\cgizard\.gradle\caches\modules-2\files-2.1\org.hamcrest\hamcrest-core\1.3\42a25dc3219429f0e5d060061f71acb49bf010a0\hamcrest-core-1.3.jar;C:\Users\cgizard\.gradle\caches\transforms-2\files-2.1\922a0c9297f2d03379e4b195504ad7ef\jars\classes.jar;C:\Users\cgizard\.gradle\caches\transforms-2\files-2.1\922a0c9297f2d03379e4b195504ad7ef\res;C:\Users\cgizard\.gradle\caches\modules-2\files-2.1\com.github.stephanenicolas.toothpick\toothpick-testing-junit4\2.1.0\1a0a91062eec70ce89df58445ce3ed464710f6b4\toothpick-testing-junit4-2.1.0.jar;C:\Users\cgizard\.gradle\caches\modules-2\files-2.1\com.squareup.picasso\picasso\2.5.2\7446d06ec8d4f7ffcc53f1da37c95f200dcb9387\picasso-2.5.2.jar;C:\Users\cgizard\.gradle\caches\transforms-2\files-2.1\de0270a3cec0e24071fbe4e8f6f029fe\jars\classes.jar;C:\Users\cgizard\.gradle\caches\modules-2\files-2.1\com.squareup.moshi\moshi\1.4.0\d67ad038adfd55dc276488a54f4944dfae5ff8ec\moshi-1.4.0.jar;C:\Users\cgizard\.gradle\caches\modules-2\files-2.1\com.squareup.retrofit2\adapter-rxjava2\2.3.0\f436637f9500ab5b8bc32afe556373180894b4a5\adapter-rxjava2-2.3.0.jar;C:\Users\cgizard\.gradle\caches\transforms-2\files-2.1\d4e2cc3dca16e6dad544f6ba21d3d8ba\jars\classes.jar;C:\Users\cgizard\.gradle\caches\transforms-2\files-2.1\d4e2cc3dca16e6dad544f6ba21d3d8ba\res;C:\Users\cgizard\.gradle\caches\modules-2\files-2.1\io.mockk\mockk-agent-api\1.9.3\467c1fd4867fc49b98a7de421a717b619767abfe\mockk-agent-api-1.9.3.jar;C:\Users\cgizard\.gradle\caches\modules-2\files-2.1\net.bytebuddy\byte-buddy-agent\1.9.10\9674aba5ee793e54b864952b001166848da0f26b\byte-buddy-agent-1.9.10.jar;C:\Users\cgizard\.gradle\caches\modules-2\files-2.1\net.bytebuddy\byte-buddy\1.9.10\211a2b4d3df1eeef2a6cacf78d74a1f725e7a840\byte-buddy-1.9.10.jar;C:\Users\cgizard\.gradle\caches\modules-2\files-2.1\androidx.collection\collection\1.0.0\42858b26cafdaa69b6149f45dfc2894007bc2c7a\collection-1.0.0.jar;C:\Users\cgizard\.gradle\caches\transforms-2\files-2.1\86a27f23c9e1b592a24a90599f793079\jars\classes.jar;C:\Users\cgizard\.gradle\caches\transforms-2\files-2.1\d3aa18d38fcbd738ef38c227aa305119\jars\classes.jar;C:\Users\cgizard\Documents\android\TP\tp-hands-on\app\build\intermediates\sourceFolderJavaResources\test\debug;C:\Users\cgizard\Documents\android\TP\tp-hands-on\app\build\intermediates\sourceFolderJavaResources\debug;C:\Users\cgizard\.gradle\caches\transforms-2\files-2.1\ccfdb9ac49af9cfd99a730012c5e5686\android.jar" com.intellij.rt.execution.junit.JUnitStarter -ideVersion5 -junit4 weather.ekamp.com.weatherappkotlin.UseCase.GetAddressUseCaseTest
toothpick.locators.NoFactoryFoundException: No factory could be found for class android.location.Geocoder. Check that the class has either a @Inject annotated constructor or contains @Inject annotated members.
at toothpick.locators.FactoryLocator.getFactory(FactoryLocator.java:21)
at toothpick.ScopeImpl.lookupProvider(ScopeImpl.java:329)
at toothpick.ScopeImpl.getInstance(ScopeImpl.java:58)
at toothpick.ScopeImpl.getInstance(ScopeImpl.java:49)
at weather.ekamp.com.weatherappkotlin.usecase.GetAddressUseCase__MemberInjector.inject(GetAddressUseCase__MemberInjector.java:12)
at weather.ekamp.com.weatherappkotlin.usecase.GetAddressUseCase__MemberInjector.inject(GetAddressUseCase__MemberInjector.java:9)
at toothpick.InjectorImpl.inject(InjectorImpl.java:23)
at toothpick.Toothpick.inject(Toothpick.java:163)
at weather.ekamp.com.weatherappkotlin.usecase.GetAddressUseCase.<init>(GetAddressUseCase.kt:21)
at weather.ekamp.com.weatherappkotlin.UseCase.GetAddressUseCaseTest.getAddressUseCaseTest(GetAddressUseCaseTest.kt:60)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
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.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
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 org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)
Caused by: java.lang.ClassNotFoundException: android.location.Geocoder__Factory
at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:331)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:264)
at toothpick.locators.FactoryLocator.getFactory(FactoryLocator.java:18)
... 32 more
Process finished with exit code -1
My useCase:
package weather.ekamp.com.weatherappkotlin.usecase
import android.app.Application
import android.location.Location
import io.reactivex.Observable
import toothpick.Toothpick
import weather.ekamp.com.weatherappkotlin.model.location.UserLocationManager
import javax.inject.Inject
class GetLocationUseCase constructor(application: Application) {
@Inject
lateinit var userLocationManager: UserLocationManager
init {
val activityScope = Toothpick.openScopes(application, this)
Toothpick.inject(this, activityScope)
}
fun execute(): Observable<Location> {
return userLocationManager.observeLocation()
}
}
and my test file (my test does nothing actually, i will improve my test when my problem will be solve).
package weather.ekamp.com.weatherappkotlin.UseCase
import android.app.Application
import android.location.Address
import android.location.Geocoder
import android.location.Location
import io.mockk.MockKAnnotations
import io.mockk.every
import io.mockk.impl.annotations.MockK
import io.reactivex.android.plugins.RxAndroidPlugins
import io.reactivex.schedulers.Schedulers
import io.reactivex.subjects.BehaviorSubject
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import toothpick.testing.ToothPickRule
import weather.ekamp.com.weatherappkotlin.model.location.UserLocationManager
import weather.ekamp.com.weatherappkotlin.usecase.GetAddressUseCase
import java.util.Locale
class GetAddressUseCaseTest {
private val toothPickRule = ToothPickRule(this)
@Rule get
@MockK
internal lateinit var application: Application
@MockK
internal lateinit var geocoder: Geocoder
@MockK
internal lateinit var userLocationManager: UserLocationManager
@Before
fun setup() {
MockKAnnotations.init(this)
toothPickRule.setScopeName(application)
toothPickRule.inject(this)
RxAndroidPlugins.setInitMainThreadSchedulerHandler { Schedulers.trampoline() }
}
@Test
fun getAddressUseCaseTest() {
// Given
val test: BehaviorSubject<Location> = BehaviorSubject.create()
val latitude = 65.2
val longitude = 22.8
val address = Address(Locale("France"))
val listOfAddress = ArrayList<Address>().apply {
add(address)
}
every { geocoder.getFromLocation(latitude, longitude, 1) } returns listOfAddress
every { userLocationManager.observeLocation() } returns test
// When
val expectedResult = GetAddressUseCase(application).execute()
// Then
}
}
I also have a binding file which looks like that:
package weather.ekamp.com.weatherappkotlin.common.application
import android.app.Application
import android.location.Geocoder
import okhttp3.OkHttpClient
import retrofit2.CallAdapter
import retrofit2.Converter
import toothpick.config.Module
import weather.ekamp.com.weatherappkotlin.common.inject.GeocoderProvider
import weather.ekamp.com.weatherappkotlin.common.inject.network.WeatherApiProvider
import weather.ekamp.com.weatherappkotlin.common.inject.network.generic.CallAdapterFactoryProvider
import weather.ekamp.com.weatherappkotlin.common.inject.network.generic.ConvertorFactoryProvider
import weather.ekamp.com.weatherappkotlin.common.inject.network.generic.OkHttpClientProvider
import weather.ekamp.com.weatherappkotlin.model.weather.WeatherApi
class WeatherApplicationModule(application: Application) : Module() {
init {
// Manager
bind(Geocoder::class.java).toProviderInstance(GeocoderProvider(application))
// web Api
bind(WeatherApi::class.java).toProvider(WeatherApiProvider::class.java)
// OkHttp
bind(OkHttpClient::class.java).toProvider(OkHttpClientProvider::class.java).providesSingletonInScope()
bind(Converter.Factory::class.java).toProvider(ConvertorFactoryProvider::class.java)
bind(CallAdapter.Factory::class.java).toProvider(CallAdapterFactoryProvider::class.java)
}
}
I install my modules in the application. My useCase is call in a viewModel which doesn't contain TP.
I also try to Inject my useCase directly in my test class but it's not working.
Does someone have an idea ?
Thank's !
Hi @ClaireGizard ,
I see a few problems there:
- Inside the test class, i see that you are calling
toothPickRule.inject(this)
, but I don't see any class being injected (the class under Test). - I cannot see
WeatherApplicationModule
being installed inside the tests. Still, if you wanna use mocks for all your dependencies, you shouldn't need to install it. - Right now
ToothPickRule
only grabs mocks from the annotations with name@Mock
, supporting Mockito and EasyMock. Do you want to create an issue so we add support toMockK
?
Anyway, to provide you a working code, I'd need to see the code that you are testing: GetAddressUseCase
.
Hi @dlemures ! Sorry for my late response. I tried to find a solution by creating another simple project. I solved the first and the third problem but i didn't find a solution for the second. In my second project i have an error on the test and i didn't find a solution and i hope you can help me. Here there is my code:
package com.example.viewmodeltests
import android.app.Application
import android.location.Address
import android.location.Geocoder
import io.reactivex.Single
import javax.inject.Inject
import javax.inject.Provider
class GetAddressUseCase @Inject constructor() {
@Inject
lateinit var geocoder: Geocoder
private val latitude = 48.117266
private val longitude = -1.6777926
fun execute(): Single<Address> {
return Single.just(geocoder.getFromLocation(latitude, longitude, 1))
.filter { it.isNotEmpty() }
.map { it.first() }
.toSingle()
}
}
class GeocoderProvider(var application: Application) : Provider<Geocoder> {
///////////////////////////////////////////////////////////////////////////
// SPECIALISATION
///////////////////////////////////////////////////////////////////////////
override fun get(): Geocoder {
return Geocoder(application)
}
}
package com.example.viewmodeltests
import io.reactivex.Single
import javax.inject.Inject
class GetTextUseCase @Inject constructor() {
fun execute(): Single<String> {
return Single.just("Plaf")
}
}
package com.example.viewmodeltests;
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProviders
import kotlinx.android.synthetic.main.activity_main.*
import toothpick.Toothpick
import toothpick.config.Module
import javax.inject.Inject
class MainActivity : AppCompatActivity() {
@Inject
lateinit var viewModel: MainViewModelInterface
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
//viewModel = ViewModelProviders.of(this).get(MainViewModel::class.java)
Toothpick.openScopes(application, this).also {
it.installModules(ActivityModule(this))
Toothpick.inject(this, it)
}
viewModel.observeText()
.observe(this, Observer {
it?.apply {
textView.text = it
}
})
viewModel.observeAddress()
.observe(this, Observer {
it?.apply {
address.text = it
}
})
button.setOnClickListener {
viewModel.updateText()
}
}
}
class ActivityModule(mainActivity: MainActivity) : Module() {
init {
bind(MainViewModelInterface::class.java).toInstance(ViewModelProviders.of(mainActivity).get(MainViewModel::class.java))
}
}
package com.example.viewmodeltests
import android.app.Application
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.CompositeDisposable
import io.reactivex.schedulers.Schedulers
import toothpick.Toothpick
import javax.inject.Inject
class MainViewModel @Inject constructor(application: Application) : MainViewModelInterface, AndroidViewModel(application) {
@Inject
lateinit var getTextUseCase: GetTextUseCase
@Inject
lateinit var getAddressUseCase: GetAddressUseCase
private val text: MutableLiveData<String> = MutableLiveData()
private val address: MutableLiveData<String> = MutableLiveData()
private val disposableSubscriptions: CompositeDisposable = CompositeDisposable()
init {
Toothpick.openScopes(application, this).also {
Toothpick.inject(this, it)
}
text.postValue("Plouf")
address.postValue("Paris")
}
override fun observeText(): LiveData<String> {
return text
}
override fun observeAddress(): LiveData<String> {
return address
}
override fun onDestroy() {
disposableSubscriptions.dispose()
Toothpick.closeScope(this)
super.onCleared()
}
override fun updateText() {
getTextUseCase.execute()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.doOnSuccess {
text.postValue(it)
}
.subscribeWith(RxLogSingleSubscriber("getTextUseCase"))
.also {
disposableSubscriptions.add(it)
}
getAddressUseCase.execute()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.doOnSuccess {
address.postValue(it.locality)
}
.subscribeWith(RxLogSingleSubscriber("getAddressUseCase"))
.also {
disposableSubscriptions.add(it)
}
}
}
package com.example.viewmodeltests
import android.app.Application
import android.location.Geocoder
import toothpick.Toothpick
import toothpick.config.Module
import toothpick.configuration.Configuration
import toothpick.smoothie.module.SmoothieApplicationModule
class ViewModelTestsApplication : Application() {
override fun onCreate() {
super.onCreate()
initToothpick()
}
///////////////////////////////////////////////////////////////////////////
// PRIVATE METHODS
///////////////////////////////////////////////////////////////////////////
private fun initToothpick() {
val configuration = if (BuildConfig.DEBUG) Configuration.forDevelopment() else Configuration.forProduction()
Toothpick.setConfiguration(configuration)
Toothpick.openScope(this).let {
it.installModules(
ApplicationModule(this),
SmoothieApplicationModule(this)
)
}
}
class ApplicationModule(application: Application) : Module() {
init {
bind(Geocoder::class.java).toProviderInstance(GeocoderProvider(application))
}
}
}
And my test file:
package com.example.viewmodeltests
import androidx.arch.core.executor.testing.InstantTaskExecutorRule
import androidx.lifecycle.Observer
import io.mockk.MockKAnnotations
import io.mockk.every
import io.mockk.impl.annotations.InjectMockKs
import io.mockk.mockk
import io.mockk.verify
import io.reactivex.android.plugins.RxAndroidPlugins
import io.reactivex.schedulers.Schedulers
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import toothpick.testing.ToothPickRule
class MainViewModelTests {
@get:Rule
var toothPickRule = ToothPickRule(this, "test scope")
@get:Rule
var instantTaskExecutorRule = InstantTaskExecutorRule()
@InjectMockKs
lateinit var mainViewModel: MainViewModel
@Before
fun before() {
MockKAnnotations.init(this)
RxAndroidPlugins.setInitMainThreadSchedulerHandler { Schedulers.trampoline() }
toothPickRule.inject(this)
}
@Test
fun checkTextAfterInitialization() {
// Given
val observer = mockk<Observer<String>>()
every { observer.onChanged(any()) } returns Unit
// When
mainViewModel.observeText().observeForever(observer)
// Then
verify {
observer.onChanged("Plouf")
}
}
// Test to check the state after a click
@Test
fun checkTextAfterClick() {
// Given
val observer = mockk<Observer<String>>()
every { observer.onChanged(any()) } returns Unit
// When
mainViewModel.observeText().observeForever(observer)
mainViewModel.updateText()
// Then
verify {
observer.onChanged("Plaf")
}
}
}
And there is my stacktrace:
io.mockk.MockKException: No matching constructors found:
constructor(application : android.app.Application = <not able to lookup>)
at io.mockk.impl.annotations.MockInjector.constructorInjection(MockInjector.kt:20)
at io.mockk.impl.annotations.JvmMockInitializer.doInjection(JvmMockInitializer.kt:86)
at io.mockk.impl.annotations.JvmMockInitializer.initMock(JvmMockInitializer.kt:64)
at io.mockk.impl.annotations.JvmMockInitializer.initAnnotatedMocks(JvmMockInitializer.kt:22)
at com.example.viewmodeltests.MainViewModelTests.before(MainViewModelTests.kt:88)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
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.RunBefores.evaluate(RunBefores.java:24)
at org.mockito.internal.junit.JUnitRule$1.evaluateSafely(JUnitRule.java:52)
at org.mockito.internal.junit.JUnitRule$1.evaluate(JUnitRule.java:43)
at org.junit.rules.TestWatcher$1.evaluate(TestWatcher.java:55)
at toothpick.testing.ToothPickStatement.evaluate(ToothPickStatement.java:17)
at org.junit.rules.RunRules.evaluate(RunRules.java:20)
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 org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)
If succeded to do some tests on my use case but i failed on the viewModel. I don't understand why. Do you have an idea ?
Thank's
Claire
@Claire, I think your mockito rule is useless ;), even if it doesn't change the behavior/issue.
Le jeu. 1 août 2019 à 14:24, ClaireGizard [email protected] a écrit :
Hi @dlemures https://github.com/dlemures ! Sorry for my late response. I tried to find a solution by creating another simple project. I solved the first and the third problem but i didn't find a solution for the second. In my second project i have an error on the test and i didn't find a solution and i hope you can help me. Here there is my code:
package com.example.viewmodeltests
import android.app.Application import android.location.Address import android.location.Geocoder import io.reactivex.Single import javax.inject.Inject import javax.inject.Provider
class GetAddressUseCase @Inject constructor() {
@Inject lateinit var geocoder: Geocoder private val latitude = 48.117266 private val longitude = -1.6777926 fun execute(): Single<Address> { return Single.just(geocoder.getFromLocation(latitude, longitude, 1)) .filter { it.isNotEmpty() } .map { it.first() } .toSingle() }
}
class GeocoderProvider(var application: Application) : Provider<Geocoder> {
/////////////////////////////////////////////////////////////////////////// // SPECIALISATION /////////////////////////////////////////////////////////////////////////// override fun get(): Geocoder { return Geocoder(application) }
}
package com.example.viewmodeltests
import io.reactivex.Single import javax.inject.Inject
class GetTextUseCase @Inject constructor() {
fun execute(): Single<String> { return Single.just("Plaf") }
}
package com.example.viewmodeltests;
import android.os.Bundle import androidx.appcompat.app.AppCompatActivity import androidx.lifecycle.Observer import androidx.lifecycle.ViewModelProviders import kotlinx.android.synthetic.main.activity_main.* import toothpick.Toothpick import toothpick.config.Module import javax.inject.Inject
class MainActivity : AppCompatActivity() {
@Inject lateinit var viewModel: MainViewModelInterface override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) //viewModel = ViewModelProviders.of(this).get(MainViewModel::class.java) Toothpick.openScopes(application, this).also { it.installModules(ActivityModule(this)) Toothpick.inject(this, it) } viewModel.observeText() .observe(this, Observer { it?.apply { textView.text = it } }) viewModel.observeAddress() .observe(this, Observer { it?.apply { address.text = it } }) button.setOnClickListener { viewModel.updateText() } }
}
class ActivityModule(mainActivity: MainActivity) : Module() { init { bind(MainViewModelInterface::class.java).toInstance(ViewModelProviders.of(mainActivity).get(MainViewModel::class.java)) } }
package com.example.viewmodeltests
import android.app.Application import androidx.lifecycle.AndroidViewModel import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.disposables.CompositeDisposable import io.reactivex.schedulers.Schedulers import toothpick.Toothpick import javax.inject.Inject
class MainViewModel @Inject constructor(application: Application) : MainViewModelInterface, AndroidViewModel(application) {
@Inject lateinit var getTextUseCase: GetTextUseCase @Inject lateinit var getAddressUseCase: GetAddressUseCase private val text: MutableLiveData<String> = MutableLiveData() private val address: MutableLiveData<String> = MutableLiveData() private val disposableSubscriptions: CompositeDisposable = CompositeDisposable() init { Toothpick.openScopes(application, this).also { Toothpick.inject(this, it) } text.postValue("Plouf") address.postValue("Paris") } override fun observeText(): LiveData<String> { return text } override fun observeAddress(): LiveData<String> { return address } override fun onDestroy() { disposableSubscriptions.dispose() Toothpick.closeScope(this) super.onCleared() } override fun updateText() { getTextUseCase.execute() .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .doOnSuccess { text.postValue(it) } .subscribeWith(RxLogSingleSubscriber("getTextUseCase")) .also { disposableSubscriptions.add(it) } getAddressUseCase.execute() .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .doOnSuccess { address.postValue(it.locality) } .subscribeWith(RxLogSingleSubscriber("getAddressUseCase")) .also { disposableSubscriptions.add(it) } }
}
package com.example.viewmodeltests
import android.app.Application import android.location.Geocoder import toothpick.Toothpick import toothpick.config.Module import toothpick.configuration.Configuration import toothpick.smoothie.module.SmoothieApplicationModule
class ViewModelTestsApplication : Application() {
override fun onCreate() { super.onCreate() initToothpick() } /////////////////////////////////////////////////////////////////////////// // PRIVATE METHODS /////////////////////////////////////////////////////////////////////////// private fun initToothpick() { val configuration = if (BuildConfig.DEBUG) Configuration.forDevelopment() else Configuration.forProduction() Toothpick.setConfiguration(configuration) Toothpick.openScope(this).let { it.installModules( ApplicationModule(this), SmoothieApplicationModule(this) ) } } class ApplicationModule(application: Application) : Module() { init { bind(Geocoder::class.java).toProviderInstance(GeocoderProvider(application)) } }
}
And my test file:
package com.example.viewmodeltests
import androidx.arch.core.executor.testing.InstantTaskExecutorRule import androidx.lifecycle.Observer import io.mockk.MockKAnnotations import io.mockk.every import io.mockk.impl.annotations.InjectMockKs import io.mockk.mockk import io.mockk.verify import io.reactivex.android.plugins.RxAndroidPlugins import io.reactivex.schedulers.Schedulers import org.junit.Before import org.junit.Rule import org.junit.Test import org.mockito.junit.MockitoJUnit import toothpick.testing.ToothPickRule
class MainViewModelTests {
@get:Rule var mockitoRule = MockitoJUnit.rule() @get:Rule var toothPickRule = ToothPickRule(this, "test scope") @get:Rule var instantTaskExecutorRule = InstantTaskExecutorRule() @InjectMockKs lateinit var mainViewModel: MainViewModel @Before fun before() { MockKAnnotations.init(this) RxAndroidPlugins.setInitMainThreadSchedulerHandler { Schedulers.trampoline() } toothPickRule.inject(this) } @Test fun checkTextAfterInitialization() { // Given val observer = mockk<Observer<String>>() every { observer.onChanged(any()) } returns Unit // When mainViewModel.observeText().observeForever(observer) // Then verify { observer.onChanged("Plouf") } } // Test to check the state after a click @Test fun checkTextAfterClick() { // Given val observer = mockk<Observer<String>>() every { observer.onChanged(any()) } returns Unit // When mainViewModel.observeText().observeForever(observer) mainViewModel.updateText() // Then verify { observer.onChanged("Plaf") } }
}
And there is my stacktrace:
io.mockk.MockKException: No matching constructors found: constructor(application : android.app.Application =
) at io.mockk.impl.annotations.MockInjector.constructorInjection(MockInjector.kt:20) at io.mockk.impl.annotations.JvmMockInitializer.doInjection(JvmMockInitializer.kt:86) at io.mockk.impl.annotations.JvmMockInitializer.initMock(JvmMockInitializer.kt:64) at io.mockk.impl.annotations.JvmMockInitializer.initAnnotatedMocks(JvmMockInitializer.kt:22) at com.example.viewmodeltests.MainViewModelTests.before(MainViewModelTests.kt:88) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) 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.RunBefores.evaluate(RunBefores.java:24) at org.mockito.internal.junit.JUnitRule$1.evaluateSafely(JUnitRule.java:52) at org.mockito.internal.junit.JUnitRule$1.evaluate(JUnitRule.java:43) at org.junit.rules.TestWatcher$1.evaluate(TestWatcher.java:55) at toothpick.testing.ToothPickStatement.evaluate(ToothPickStatement.java:17) at org.junit.rules.RunRules.evaluate(RunRules.java:20) 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 org.junit.runner.JUnitCore.run(JUnitCore.java:137) at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68) at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47) at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242) at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)
If succeded to do some tests on my use case but i failed on the viewModel. I don't understand why. Do you have an idea ?
Thank's
Claire
— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/stephanenicolas/toothpick/issues/333?email_source=notifications&email_token=ABSAEWIVQNPXDC7U5DHSJ3TQCLIV3A5CNFSM4HSIUAYKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOD3KNBJY#issuecomment-517263527, or mute the thread https://github.com/notifications/unsubscribe-auth/ABSAEWKFKCES47QJY2MSNDLQCLIV3ANCNFSM4HSIUAYA .
effectively, i deleted it !
Hi @ClaireGizard ,
Sorry for the late response, we have been quite busy releasing the 3rd version.
The error you are having is with mockK
. It is trying to find a mock of Application
to inject in the MainViewModel
constructor, but you haven't defined any:
class MainViewModelTests {
@get:Rule
var toothPickRule = ToothPickRule(this, "test scope")
@get:Rule
var instantTaskExecutorRule = InstantTaskExecutorRule()
@InjectMockKs // <- USING MOCKK TO INJECT THE DEPENDENCIES
lateinit var mainViewModel: MainViewModel
@Before
fun before() {
MockKAnnotations.init(this) // <- YOU DONT HAVE ANY MOCK ANNOTATION
RxAndroidPlugins.setInitMainThreadSchedulerHandler { Schedulers.trampoline() }
toothPickRule.inject(this) // <- DOING NOTHING
}
}
Even though you are using toothPickRule.inject(this)
, you are not using TP to inject MainViewModel
. You are using mockK instead. You need to use one or the other.
I've not used mockK before, but if you decide to with that option, I think that something like this should work:
class MainViewModelTests {
@get:Rule
var instantTaskExecutorRule = InstantTaskExecutorRule()
@MockK
lateinit var application: Application
@InjectMockKs
lateinit var mainViewModel: MainViewModel
@Before
fun before() {
MockKAnnotations.init(this)
RxAndroidPlugins.setInitMainThreadSchedulerHandler { Schedulers.trampoline() }
}
}