~~editing~~ `Day 52` - Completed Part 11 of _<http...
# 100daysofkotlin-2021
b
editing
Day 52
• Completed Part 11 of

Testing on Android

course
Self-Comment
Issues for the day: ◦ Issue with Kotlin IntRanges, fixed by upgrading from 1.4.31 to 1.4.32 (Approx. 1 hour to fix)Focus: ◦ Trying new way to document daily summary. With an early edit post to leave copies of my issues & how I solved them. Along with any screenshots / info I find useful to keep a record of. ▪︎ Hope you (yes you), don't mind all the commentary passed just Kotlin challenge!.. I say this even though I've been doing it for 52 posts now. heh ◦ Covered Testing with ViewModels, Dagger-Hilt, and Fragments. I had a pretty solid understanding with ViewModels & Hilt Testing, but I haven't been using Fragments in my project(s) since I am using Compose with 0 Fragments.. ▪︎ I don't think this part of testing will stick like the other two, although I'm pushing through it regardless for exposure. ◦ Started Part 12 to test Navigation with Mockito and Espresso. Had some early issues with handling Navigation as he isn't covering building the layout for it. But I managed to get through the first few minutes. ▪︎ Excited to cover a Mockito and Espresso. I hear MockK, Mockito, and Espresso often when testing comes up. I believe Espresso is used for Android UI tests, but that's all I know of it. As for mocking libraries, I know their used for mocking.. but do they mock logic tests or UI tests? Will find out tomorrow!Thoughts: ◦ Seems I've been more productive in the mornings than evening lately. I'm not sure when this started as it's always been the opposite. 😅 ◦ Not sure where to store the read list below, but it's in some of my goals to go through. I may make it as part of my morning read. ◦ Did not do the leetcode problem again, I don't think I've got the motivation for it until I finish up some testing practice. ◦ Thinking of finding a discord group or reaching out on Reddit for a small programming group. I'm not familiar with them, but since coming back to the States and moving to a new area.. All I've done is study, and I don't know anyone with similar interests. Could be good to get some motivation that way. 🤔 Just a summed up thought on this vast topic ◦ My daily log is always centered more on thoughts vs accomplishments. Should I change this and move my thoughts to thread in post?
Goals Tomorrow
• Complete

Testing on Android

course (Part 12-16) • Read List: ◦ Start or bookmark Medium book? : Programming DSLs in Kotlin ▪︎ Part of: Directory of Pragmatic Programmer Books on Medium ◦ Read Medium Article: Unit Testing with Kotlin Coroutines: The Android Way
1
Issue with com (test)
Copy code
Exception in thread "Test worker" java.lang.IllegalStateException: Module with the Main dispatcher had failed to initialize. For tests Dispatchers.setMain from kotlinx-coroutines-test module can be used
	at kotlinx.coroutines.internal.MissingMainCoroutineDispatcher.missing(MainDispatchers.kt:110)
	at kotlinx.coroutines.internal.MissingMainCoroutineDispatcher.isDispatchNeeded(MainDispatchers.kt:91)
	at kotlinx.coroutines.internal.DispatchedContinuationKt.resumeCancellableWith(DispatchedContinuation.kt:302)
	at kotlinx.coroutines.intrinsics.CancellableKt.startCoroutineCancellable(Cancellable.kt:30)
	at kotlinx.coroutines.intrinsics.CancellableKt.startCoroutineCancellable$default(Cancellable.kt:27)
	at kotlinx.coroutines.CoroutineStart.invoke(CoroutineStart.kt:110)
	at kotlinx.coroutines.AbstractCoroutine.start(AbstractCoroutine.kt:158)
	at kotlinx.coroutines.BuildersKt__Builders_commonKt.launch(Builders.common.kt:56)
	at kotlinx.coroutines.BuildersKt.launch(Unknown Source)
	at kotlinx.coroutines.BuildersKt__Builders_commonKt.launch$default(Builders.common.kt:49)
	at kotlinx.coroutines.BuildersKt.launch$default(Unknown Source)
	at com.lid.shoppinglisttesting.ui.ShoppingViewModel.insertShoppingItemIntoDb(ShoppingViewModel.kt:43)
	at com.lid.shoppinglisttesting.ui.ShoppingViewModel.insertShoppingItem(ShoppingViewModel.kt:70)
	at com.lid.shoppinglisttesting.ui.ShoppingViewModelTest.insert Shopping item with valid input, returns success(ShoppingViewModelTest.kt:75)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:566)
	at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:59)
	at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
	at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:56)
	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.rules.TestWatcher$1.evaluate(TestWatcher.java:61)
	at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
	at org.junit.runners.BlockJUnit4ClassRunner$1.evaluate(BlockJUnit4ClassRunner.java:100)
	at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:366)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:103)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:63)
	at org.junit.runners.ParentRunner$4.run(ParentRunner.java:331)
	at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:79)
	at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329)
	at org.junit.runners.ParentRunner.access$100(ParentRunner.java:66)
	at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:293)
	at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
	at org.junit.runners.ParentRunner.run(ParentRunner.java:413)
	at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecutor.runTestClass(JUnitTestClassExecutor.java:110)
	at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecutor.execute(JUnitTestClassExecutor.java:58)
	at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecutor.execute(JUnitTestClassExecutor.java:38)
	at org.gradle.api.internal.tasks.testing.junit.AbstractJUnitTestClassProcessor.processTestClass(AbstractJUnitTestClassProcessor.java:62)
	at org.gradle.api.internal.tasks.testing.SuiteTestClassProcessor.processTestClass(SuiteTestClassProcessor.java:51)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:566)
	at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:36)
	at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
	at org.gradle.internal.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:33)
	at org.gradle.internal.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:94)
	at com.sun.proxy.$Proxy2.processTestClass(Unknown Source)
	at org.gradle.api.internal.tasks.testing.worker.TestWorker.processTestClass(TestWorker.java:121)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:566)
	at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:36)
	at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
	at org.gradle.internal.remote.internal.hub.MessageHubBackedObjectConnection$DispatchWrapper.dispatch(MessageHubBackedObjectConnection.java:182)
	at org.gradle.internal.remote.internal.hub.MessageHubBackedObjectConnection$DispatchWrapper.dispatch(MessageHubBackedObjectConnection.java:164)
	at org.gradle.internal.remote.internal.hub.MessageHub$Handler.run(MessageHub.java:414)
	at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:64)
	at org.gradle.internal.concurrent.ManagedExecutorImpl$1.run(ManagedExecutorImpl.java:48)
	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
	at org.gradle.internal.concurrent.ThreadFactoryImpl$ManagedThreadRunnable.run(ThreadFactoryImpl.java:56)
	at java.base/java.lang.Thread.run(Thread.java:829)
Caused by: java.lang.RuntimeException: Method getMainLooper in android.os.Looper not mocked. See <http://g.co/androidstudio/not-mocked> for details.
	at android.os.Looper.getMainLooper(Looper.java)
	at kotlinx.coroutines.android.AndroidDispatcherFactory.createDispatcher(HandlerDispatcher.kt:55)
	at kotlinx.coroutines.android.AndroidDispatcherFactory.createDispatcher(HandlerDispatcher.kt:52)
	at kotlinx.coroutines.internal.MainDispatchersKt.tryCreateDispatcher(MainDispatchers.kt:57)
	at kotlinx.coroutines.test.internal.TestMainDispatcher.getDelegate(MainTestDispatcher.kt:19)
	at kotlinx.coroutines.test.internal.TestMainDispatcher.getImmediate(MainTestDispatcher.kt:32)
	at androidx.lifecycle.ViewModelKt.getViewModelScope(ViewModel.kt:43)
	... 55 more
Does not occur in com (androidTest) because we don't have MainDispatcher in (test) as it relies on MainLooper which relies on a real app(android device). To fix: In com (test), add class:
Copy code
@ExperimentalCoroutinesApi
class MainCoroutineRule @ExperimentalCoroutinesApi constructor(
    private val dispatcher: CoroutineDispatcher = TestCoroutineDispatcher()
) : TestWatcher(), TestCoroutineScope by TestCoroutineScope(dispatcher) {

    override fun starting(description: Description?) {
        super.starting(description)
        Dispatchers.setMain(dispatcher)
    }

    override fun finished(description: Description?) {
        super.finished(description)
        cleanupTestCoroutines()
        Dispatchers.resetMain()
    }
}
In ViewModelTest, add rule:
Copy code
@get:Rule
    var mainCoroutineRule = MainCoroutineRule()
Issue when trying to test fragment in isolation with Hilt as DI. Error seems to stem from Intent / startActivity / launch
Copy code
java.lang.RuntimeException: Unable to resolve activity for: Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] cmp=com.lid.shoppinglisttesting/.HiltTestActivity (has extras) }
	at androidx.test.core.app.InstrumentationActivityInvoker.startActivity(InstrumentationActivityInvoker.java:387)
	at androidx.test.core.app.InstrumentationActivityInvoker.startActivity(InstrumentationActivityInvoker.java:416)
	at androidx.test.core.app.ActivityScenario.launchInternal(ActivityScenario.java:265)
	at androidx.test.core.app.ActivityScenario.launch(ActivityScenario.java:226)
	at com.lid.shoppinglisttesting.data.local.ShoppingDaoTest.testLaunchFragmentInHiltContainer(ShoppingDaoTest.kt:133)
	at java.lang.reflect.Method.invoke(Native Method)
	at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:59)
	at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
	at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:56)
	at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
	at androidx.test.internal.runner.junit4.statement.RunBefores.evaluate(RunBefores.java:80)
	at androidx.test.internal.runner.junit4.statement.RunAfters.evaluate(RunAfters.java:61)
	at org.junit.rules.TestWatcher$1.evaluate(TestWatcher.java:61)
	at dagger.hilt.android.internal.testing.MarkThatRulesRanRule$1.evaluate(MarkThatRulesRanRule.java:106)
	at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
	at org.junit.runners.BlockJUnit4ClassRunner$1.evaluate(BlockJUnit4ClassRunner.java:100)
	at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:366)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:103)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:63)
	at org.junit.runners.ParentRunner$4.run(ParentRunner.java:331)
	at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:79)
	at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329)
	at org.junit.runners.ParentRunner.access$100(ParentRunner.java:66)
	at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:293)
	at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
	at org.junit.runners.ParentRunner.run(ParentRunner.java:413)
	at org.junit.runners.Suite.runChild(Suite.java:128)
	at org.junit.runners.Suite.runChild(Suite.java:27)
	at org.junit.runners.ParentRunner$4.run(ParentRunner.java:331)
	at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:79)
	at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329)
	at org.junit.runners.ParentRunner.access$100(ParentRunner.java:66)
	at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:293)
	at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
	at org.junit.runners.ParentRunner.run(ParentRunner.java:413)
	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:395)
	at android.app.Instrumentation$InstrumentationThread.run(Instrumentation.java:2205)