From 110771d0772f459d8bd3dc331ee223dfc044276f Mon Sep 17 00:00:00 2001 From: Tiger Oakes Date: Thu, 28 May 2020 17:43:40 -0700 Subject: [PATCH] [fenix] Remove Mockito --- app/build.gradle | 2 - .../mozilla/fenix/IntentReceiverActivity.kt | 2 +- .../org/mozilla/fenix/share/ShareViewModel.kt | 10 +- .../fenix/IntentReceiverActivityTest.kt | 138 +++++++++--------- .../components/AccountAbnormalitiesTest.kt | 64 ++++---- .../components/InflationAwareFeatureTest.kt | 59 ++++---- .../fenix/components/TestComponents.kt | 14 +- .../metrics/BreadcrumbRecorderTest.kt | 18 +-- .../components/metrics/MetricsUtilsTest.kt | 16 +- .../FenixSearchEngineProviderTest.kt | 16 +- .../ExternalAppBrowserActivityTest.kt | 11 +- .../customtabs/PoweredByNotificationTest.kt | 4 +- .../DynamicDownloadDialogBehaviorTest.kt | 125 ++++++++-------- .../java/org/mozilla/fenix/ext/SessionTest.kt | 10 +- .../mozilla/fenix/ext/TabCollectionTest.kt | 8 +- .../SpeechProcessingIntentProcessorTest.kt | 13 +- .../library/history/HistoryControllerTest.kt | 5 +- .../advanced/LocaleSettingsControllerTest.kt | 3 +- .../mozilla/fenix/share/ShareViewModelTest.kt | 43 +++--- .../fenix/tabtray/TabTrayViewHolderTest.kt | 10 +- buildSrc/src/main/java/Dependencies.kt | 3 - 21 files changed, 286 insertions(+), 288 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 430e1c478..f98bd3ce0 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -593,8 +593,6 @@ dependencies { testImplementation 'org.apache.maven:maven-ant-tasks:2.1.3' implementation Deps.mozilla_support_rusthttp - testImplementation Deps.mockito_core - androidTestImplementation Deps.mockito_android testImplementation Deps.mockk // For the initial release of Glean 19, we require consumer applications to diff --git a/app/src/main/java/org/mozilla/fenix/IntentReceiverActivity.kt b/app/src/main/java/org/mozilla/fenix/IntentReceiverActivity.kt index 08f2add71..05790633d 100644 --- a/app/src/main/java/org/mozilla/fenix/IntentReceiverActivity.kt +++ b/app/src/main/java/org/mozilla/fenix/IntentReceiverActivity.kt @@ -32,7 +32,7 @@ class IntentReceiverActivity : Activity() { // The intent property is nullable, but the rest of the code below // assumes it is not. If it's null, then we make a new one and open // the HomeActivity. - val intent = intent?.let { Intent(intent) } ?: Intent() + val intent = intent?.let { Intent(it) } ?: Intent() intent.stripUnwantedFlags() processIntent(intent) } diff --git a/app/src/main/java/org/mozilla/fenix/share/ShareViewModel.kt b/app/src/main/java/org/mozilla/fenix/share/ShareViewModel.kt index ecca2624a..65d25caed 100644 --- a/app/src/main/java/org/mozilla/fenix/share/ShareViewModel.kt +++ b/app/src/main/java/org/mozilla/fenix/share/ShareViewModel.kt @@ -18,7 +18,7 @@ import androidx.lifecycle.AndroidViewModel import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.viewModelScope -import kotlinx.coroutines.Dispatchers.IO +import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import mozilla.components.concept.sync.DeviceCapability import mozilla.components.feature.share.RecentAppsStorage @@ -38,6 +38,8 @@ class ShareViewModel(application: Application) : AndroidViewModel(application) { private val fxaAccountManager = application.components.backgroundServices.accountManager @VisibleForTesting internal var recentAppsStorage = RecentAppsStorage(application.applicationContext) + @VisibleForTesting + internal var ioDispatcher = Dispatchers.IO private val devicesListLiveData = MutableLiveData>(emptyList()) private val appsListLiveData = MutableLiveData>(emptyList()) @@ -49,7 +51,7 @@ class ShareViewModel(application: Application) : AndroidViewModel(application) { override fun onAvailable(network: Network?) = reloadDevices(network) private fun reloadDevices(network: Network?) { - viewModelScope.launch(IO) { + viewModelScope.launch(ioDispatcher) { fxaAccountManager.authenticatedAccount() ?.deviceConstellation() ?.refreshDevicesAsync() @@ -83,7 +85,7 @@ class ShareViewModel(application: Application) : AndroidViewModel(application) { connectivityManager?.registerNetworkCallback(networkRequest, networkCallback) // Start preparing the data as soon as we have a valid Context - viewModelScope.launch(IO) { + viewModelScope.launch(ioDispatcher) { val shareIntent = Intent(Intent.ACTION_SEND).apply { type = "text/plain" flags = Intent.FLAG_ACTIVITY_NEW_TASK @@ -98,7 +100,7 @@ class ShareViewModel(application: Application) : AndroidViewModel(application) { appsListLiveData.postValue(apps) } - viewModelScope.launch(IO) { + viewModelScope.launch(ioDispatcher) { val devices = buildDeviceList(fxaAccountManager) devicesListLiveData.postValue(devices) } diff --git a/app/src/test/java/org/mozilla/fenix/IntentReceiverActivityTest.kt b/app/src/test/java/org/mozilla/fenix/IntentReceiverActivityTest.kt index b1953edcd..436f0feee 100644 --- a/app/src/test/java/org/mozilla/fenix/IntentReceiverActivityTest.kt +++ b/app/src/test/java/org/mozilla/fenix/IntentReceiverActivityTest.kt @@ -4,42 +4,63 @@ package org.mozilla.fenix +import android.app.Activity import android.content.Intent import android.content.Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY +import io.mockk.coEvery +import io.mockk.coVerify +import io.mockk.every +import io.mockk.mockk +import io.mockk.mockkStatic import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.runBlockingTest -import mozilla.components.support.test.robolectric.testContext +import mozilla.components.feature.intent.processing.IntentProcessor import org.junit.Assert.assertEquals import org.junit.Assert.assertTrue +import org.junit.Before import org.junit.Test import org.junit.runner.RunWith -import org.mockito.Mockito.`when` -import org.mockito.Mockito.never -import org.mockito.Mockito.verify +import org.mozilla.fenix.components.IntentProcessors import org.mozilla.fenix.customtabs.ExternalAppBrowserActivity import org.mozilla.fenix.ext.components import org.mozilla.fenix.ext.settings +import org.mozilla.fenix.helpers.FenixRobolectricTestRunner import org.mozilla.fenix.shortcut.NewTabShortcutIntentProcessor +import org.mozilla.fenix.utils.Settings import org.robolectric.Robolectric -import org.mozilla.fenix.helpers.FenixRobolectricTestRunner import org.robolectric.Shadows.shadowOf @ExperimentalCoroutinesApi @RunWith(FenixRobolectricTestRunner::class) class IntentReceiverActivityTest { + private lateinit var settings: Settings + private lateinit var intentProcessors: IntentProcessors + + @Before + fun setup() { + settings = mockk() + intentProcessors = mockk() + + every { settings.openLinksInAPrivateTab } returns false + every { intentProcessors.intentProcessor } returns mockIntentProcessor() + every { intentProcessors.privateIntentProcessor } returns mockIntentProcessor() + every { intentProcessors.customTabIntentProcessor } returns mockIntentProcessor() + every { intentProcessors.privateCustomTabIntentProcessor } returns mockIntentProcessor() + every { intentProcessors.externalAppIntentProcessors } returns emptyList() + every { intentProcessors.fennecPageShortcutIntentProcessor } returns mockIntentProcessor() + every { intentProcessors.migrationIntentProcessor } returns mockIntentProcessor() + + coEvery { intentProcessors.intentProcessor.process(any()) } returns true + } + @Test fun `process intent with flag launched from history`() = runBlockingTest { - testContext.settings().openLinksInAPrivateTab = false - val intent = Intent() intent.flags = FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY - `when`(testContext.components.intentProcessors.migrationIntentProcessor.process(intent)).thenReturn(false) - `when`(testContext.components.intentProcessors.intentProcessor.process(intent)).thenReturn(true) - `when`(testContext.components.intentProcessors.customTabIntentProcessor.process(intent)).thenReturn(false) - `when`(testContext.components.intentProcessors.fennecPageShortcutIntentProcessor.process(intent)).thenReturn(false) val activity = Robolectric.buildActivity(IntentReceiverActivity::class.java, intent).get() + attachMocks(activity) activity.processIntent(intent) val shadow = shadowOf(activity) @@ -51,16 +72,13 @@ class IntentReceiverActivityTest { @Test fun `process intent with action OPEN_PRIVATE_TAB`() = runBlockingTest { - testContext.settings().openLinksInAPrivateTab = false - val intent = Intent() intent.action = NewTabShortcutIntentProcessor.ACTION_OPEN_PRIVATE_TAB - `when`(testContext.components.intentProcessors.migrationIntentProcessor.process(intent)).thenReturn(false) - `when`(testContext.components.intentProcessors.intentProcessor.process(intent)).thenReturn(false) - `when`(testContext.components.intentProcessors.customTabIntentProcessor.process(intent)).thenReturn(false) - `when`(testContext.components.intentProcessors.fennecPageShortcutIntentProcessor.process(intent)).thenReturn(false) + coEvery { intentProcessors.intentProcessor.process(intent) } returns false + coEvery { intentProcessors.customTabIntentProcessor.process(intent) } returns false val activity = Robolectric.buildActivity(IntentReceiverActivity::class.java, intent).get() + attachMocks(activity) activity.processIntent(intent) val shadow = shadowOf(activity) @@ -73,16 +91,11 @@ class IntentReceiverActivityTest { @Test fun `process intent with action OPEN_TAB`() = runBlockingTest { - testContext.settings().openLinksInAPrivateTab = false - val intent = Intent() intent.action = NewTabShortcutIntentProcessor.ACTION_OPEN_TAB - `when`(testContext.components.intentProcessors.migrationIntentProcessor.process(intent)).thenReturn(false) - `when`(testContext.components.intentProcessors.intentProcessor.process(intent)).thenReturn(false) - `when`(testContext.components.intentProcessors.customTabIntentProcessor.process(intent)).thenReturn(false) - `when`(testContext.components.intentProcessors.fennecPageShortcutIntentProcessor.process(intent)).thenReturn(false) val activity = Robolectric.buildActivity(IntentReceiverActivity::class.java, intent).get() + attachMocks(activity) activity.processIntent(intent) val shadow = shadowOf(activity) @@ -90,19 +103,13 @@ class IntentReceiverActivityTest { assertEquals(HomeActivity::class.java.name, actualIntent.component?.className) assertEquals(false, actualIntent.getBooleanExtra(HomeActivity.PRIVATE_BROWSING_MODE, false)) - assertEquals(false, actualIntent.getBooleanExtra(HomeActivity.OPEN_TO_BROWSER, true)) } @Test fun `process intent starts Activity`() = runBlockingTest { - testContext.settings().openLinksInAPrivateTab = false - val intent = Intent() - `when`(testContext.components.intentProcessors.migrationIntentProcessor.process(intent)).thenReturn(false) - `when`(testContext.components.intentProcessors.intentProcessor.process(intent)).thenReturn(true) - `when`(testContext.components.intentProcessors.customTabIntentProcessor.process(intent)).thenReturn(false) - `when`(testContext.components.intentProcessors.fennecPageShortcutIntentProcessor.process(intent)).thenReturn(false) val activity = Robolectric.buildActivity(IntentReceiverActivity::class.java, intent).get() + attachMocks(activity) activity.processIntent(intent) val shadow = shadowOf(activity) @@ -114,57 +121,45 @@ class IntentReceiverActivityTest { @Test fun `process intent with launchLinksInPrivateTab set to true`() = runBlockingTest { - testContext.settings().openLinksInAPrivateTab = true + every { settings.openLinksInAPrivateTab } returns true + + coEvery { intentProcessors.intentProcessor.process(any()) } returns false + coEvery { intentProcessors.privateIntentProcessor.process(any()) } returns true val intent = Intent() - `when`(testContext.components.intentProcessors.migrationIntentProcessor.process(intent)).thenReturn(false) - `when`(testContext.components.intentProcessors.privateIntentProcessor.process(intent)).thenReturn(true) - `when`(testContext.components.intentProcessors.privateCustomTabIntentProcessor.process(intent)).thenReturn(false) - `when`(testContext.components.intentProcessors.fennecPageShortcutIntentProcessor.process(intent)).thenReturn(false) val activity = Robolectric.buildActivity(IntentReceiverActivity::class.java, intent).get() + attachMocks(activity) activity.processIntent(intent) - // Not using mockk here because process is a suspend function - // and mockito makes this easier to read. - verify(testContext.components.intentProcessors.intentProcessor, never()).process(intent) - verify(testContext.components.intentProcessors.privateIntentProcessor).process(intent) + val normalProcessor = intentProcessors.intentProcessor + coVerify(exactly = 0) { normalProcessor.process(intent) } + coVerify { intentProcessors.privateIntentProcessor.process(intent) } } @Test fun `process intent with launchLinksInPrivateTab set to false`() = runBlockingTest { - testContext.settings().openLinksInAPrivateTab = false - val intent = Intent() - `when`(testContext.components.intentProcessors.migrationIntentProcessor.process(intent)).thenReturn(false) - `when`(testContext.components.intentProcessors.intentProcessor.process(intent)).thenReturn(true) - `when`(testContext.components.intentProcessors.customTabIntentProcessor.process(intent)).thenReturn(false) - `when`(testContext.components.intentProcessors.fennecPageShortcutIntentProcessor.process(intent)).thenReturn(false) val activity = Robolectric.buildActivity(IntentReceiverActivity::class.java, intent).get() + attachMocks(activity) activity.processIntent(intent) - // Not using mockk here because process is a suspend function - // and mockito makes this easier to read. - verify(testContext.components.intentProcessors.privateIntentProcessor, never()).process(intent) - verify(testContext.components.intentProcessors.intentProcessor).process(intent) + coVerify(exactly = 0) { intentProcessors.privateIntentProcessor.process(intent) } + coVerify { intentProcessors.intentProcessor.process(intent) } } @Test fun `process custom tab intent`() = runBlockingTest { - testContext.settings().openLinksInAPrivateTab = false - val intent = Intent() - `when`(testContext.components.intentProcessors.migrationIntentProcessor.process(intent)).thenReturn(false) - `when`(testContext.components.intentProcessors.fennecPageShortcutIntentProcessor.process(intent)).thenReturn(false) - `when`(testContext.components.intentProcessors.customTabIntentProcessor.process(intent)).thenReturn(true) + coEvery { intentProcessors.intentProcessor.process(intent) } returns false + coEvery { intentProcessors.customTabIntentProcessor.process(intent) } returns true val activity = Robolectric.buildActivity(IntentReceiverActivity::class.java, intent).get() + attachMocks(activity) activity.processIntent(intent) - // Not using mockk here because process is a suspend function - // and mockito makes this easier to read. - verify(testContext.components.intentProcessors.privateIntentProcessor, never()).process(intent) - verify(testContext.components.intentProcessors.customTabIntentProcessor).process(intent) + coVerify(exactly = 0) { intentProcessors.privateCustomTabIntentProcessor.process(intent) } + coVerify { intentProcessors.customTabIntentProcessor.process(intent) } assertEquals(ExternalAppBrowserActivity::class.java.name, intent.component!!.className) assertTrue(intent.getBooleanExtra(HomeActivity.OPEN_TO_BROWSER, false)) @@ -172,22 +167,33 @@ class IntentReceiverActivityTest { @Test fun `process private custom tab intent`() = runBlockingTest { - testContext.settings().openLinksInAPrivateTab = true + every { settings.openLinksInAPrivateTab } returns true val intent = Intent() - `when`(testContext.components.intentProcessors.migrationIntentProcessor.process(intent)).thenReturn(false) - `when`(testContext.components.intentProcessors.privateCustomTabIntentProcessor.process(intent)).thenReturn(true) - `when`(testContext.components.intentProcessors.fennecPageShortcutIntentProcessor.process(intent)).thenReturn(false) + coEvery { intentProcessors.privateCustomTabIntentProcessor.process(intent) } returns true val activity = Robolectric.buildActivity(IntentReceiverActivity::class.java, intent).get() + attachMocks(activity) activity.processIntent(intent) - // Not using mockk here because process is a suspend function - // and mockito makes this easier to read. - verify(testContext.components.intentProcessors.intentProcessor, never()).process(intent) - verify(testContext.components.intentProcessors.privateCustomTabIntentProcessor).process(intent) + val normalProcessor = intentProcessors.customTabIntentProcessor + coVerify(exactly = 0) { normalProcessor.process(intent) } + coVerify { intentProcessors.privateCustomTabIntentProcessor.process(intent) } assertEquals(ExternalAppBrowserActivity::class.java.name, intent.component!!.className) assertTrue(intent.getBooleanExtra(HomeActivity.OPEN_TO_BROWSER, false)) } + + private fun attachMocks(activity: Activity) { + mockkStatic("org.mozilla.fenix.ext.ContextKt") + every { activity.settings() } returns settings + every { activity.components.analytics } returns mockk(relaxed = true) + every { activity.components.intentProcessors } returns intentProcessors + } + + private inline fun mockIntentProcessor(): T { + return mockk { + coEvery { process(any()) } returns false + } + } } diff --git a/app/src/test/java/org/mozilla/fenix/components/AccountAbnormalitiesTest.kt b/app/src/test/java/org/mozilla/fenix/components/AccountAbnormalitiesTest.kt index 41e8f2c4c..21c0b404c 100644 --- a/app/src/test/java/org/mozilla/fenix/components/AccountAbnormalitiesTest.kt +++ b/app/src/test/java/org/mozilla/fenix/components/AccountAbnormalitiesTest.kt @@ -4,27 +4,26 @@ package org.mozilla.fenix.components +import io.mockk.Called +import io.mockk.every +import io.mockk.mockk +import io.mockk.verify import org.mozilla.fenix.helpers.FenixRobolectricTestRunner import kotlinx.coroutines.CompletableDeferred import kotlinx.coroutines.runBlocking import mozilla.components.lib.crash.CrashReporter import mozilla.components.service.fxa.manager.FxaAccountManager -import mozilla.components.support.test.argumentCaptor -import mozilla.components.support.test.mock import mozilla.components.support.test.robolectric.testContext import org.junit.Assert.assertEquals import org.junit.Assert.fail import org.junit.Test import org.junit.runner.RunWith -import org.mockito.Mockito.verifyZeroInteractions -import org.mockito.Mockito.verify -import kotlin.reflect.KClass @RunWith(FenixRobolectricTestRunner::class) class AccountAbnormalitiesTest { @Test fun `account manager must be configured`() { - val crashReporter: CrashReporter = mock() + val crashReporter: CrashReporter = mockk() // no account present val accountAbnormalities = AccountAbnormalities(testContext, crashReporter) @@ -37,7 +36,7 @@ class AccountAbnormalitiesTest { } try { - accountAbnormalities.onAuthenticated(mock(), mock()) + accountAbnormalities.onAuthenticated(mockk(), mockk()) fail() } catch (e: IllegalStateException) { assertEquals("onAuthenticated before account manager was configured", e.message) @@ -50,13 +49,13 @@ class AccountAbnormalitiesTest { assertEquals("onLoggedOut before account manager was configured", e.message) } - verifyZeroInteractions(crashReporter) + verify { crashReporter wasNot Called } } @Test fun `LogoutWithoutAuth detected`() = runBlocking { - val crashReporter: CrashReporter = mock() - val accountManager: FxaAccountManager = mock() + val crashReporter: CrashReporter = mockk(relaxed = true) + val accountManager: FxaAccountManager = mockk(relaxed = true) val accountAbnormalities = AccountAbnormalities(testContext, crashReporter, this.coroutineContext) accountAbnormalities.accountManagerInitializedAsync( @@ -66,13 +65,13 @@ class AccountAbnormalitiesTest { // Logout action must be preceded by auth. accountAbnormalities.userRequestedLogout() - assertCaughtException(crashReporter, AbnormalFxaEvent.LogoutWithoutAuth::class) + assertCaughtException(crashReporter) } @Test fun `OverlappingFxaLogoutRequest detected`() = runBlocking { - val crashReporter: CrashReporter = mock() - val accountManager: FxaAccountManager = mock() + val crashReporter: CrashReporter = mockk(relaxed = true) + val accountManager: FxaAccountManager = mockk(relaxed = true) val accountAbnormalities = AccountAbnormalities(testContext, crashReporter, this.coroutineContext) accountAbnormalities.accountManagerInitializedAsync( @@ -80,20 +79,20 @@ class AccountAbnormalitiesTest { CompletableDeferred(Unit).also { it.complete(Unit) } ).await() - accountAbnormalities.onAuthenticated(mock(), mock()) + accountAbnormalities.onAuthenticated(mockk(), mockk()) // So far, so good. A regular logout request while being authenticated. accountAbnormalities.userRequestedLogout() - verifyZeroInteractions(crashReporter) + verify { crashReporter wasNot Called } // We never saw a logout callback after previous logout request, so this is an overlapping request. accountAbnormalities.userRequestedLogout() - assertCaughtException(crashReporter, AbnormalFxaEvent.OverlappingFxaLogoutRequest::class) + assertCaughtException(crashReporter) } @Test fun `callback logout abnormalities detected`() = runBlocking { - val crashReporter: CrashReporter = mock() - val accountManager: FxaAccountManager = mock() + val crashReporter: CrashReporter = mockk(relaxed = true) + val accountManager: FxaAccountManager = mockk(relaxed = true) val accountAbnormalities = AccountAbnormalities(testContext, crashReporter, this.coroutineContext) accountAbnormalities.accountManagerInitializedAsync( @@ -103,13 +102,13 @@ class AccountAbnormalitiesTest { // User didn't request this logout. accountAbnormalities.onLoggedOut() - assertCaughtException(crashReporter, AbnormalFxaEvent.UnexpectedFxaLogout::class) + assertCaughtException(crashReporter) } @Test fun `login happy case + disappearing account detected`() = runBlocking { - val crashReporter: CrashReporter = mock() - val accountManager: FxaAccountManager = mock() + val crashReporter: CrashReporter = mockk(relaxed = true) + val accountManager: FxaAccountManager = mockk(relaxed = true) val accountAbnormalities = AccountAbnormalities(testContext, crashReporter, this.coroutineContext) accountAbnormalities.accountManagerInitializedAsync( @@ -117,8 +116,9 @@ class AccountAbnormalitiesTest { CompletableDeferred(Unit).also { it.complete(Unit) } ).await() - accountAbnormalities.onAuthenticated(mock(), mock()) - verifyZeroInteractions(crashReporter) + accountAbnormalities.onAuthenticated(mockk(), mockk()) + verify { crashReporter wasNot Called } + every { accountManager.authenticatedAccount() } returns null // Pretend we restart, and instantiate a new middleware instance. val accountAbnormalities2 = AccountAbnormalities(testContext, crashReporter, this.coroutineContext) @@ -129,13 +129,13 @@ class AccountAbnormalitiesTest { CompletableDeferred(Unit).also { it.complete(Unit) } ).await() - assertCaughtException(crashReporter, AbnormalFxaEvent.MissingExpectedAccountAfterStartup::class) + assertCaughtException(crashReporter) } @Test fun `logout happy case`() = runBlocking { - val crashReporter: CrashReporter = mock() - val accountManager: FxaAccountManager = mock() + val crashReporter: CrashReporter = mockk() + val accountManager: FxaAccountManager = mockk(relaxed = true) val accountAbnormalities = AccountAbnormalities(testContext, crashReporter, this.coroutineContext) accountAbnormalities.accountManagerInitializedAsync( @@ -144,14 +144,14 @@ class AccountAbnormalitiesTest { ).await() // We saw an auth event, then user requested a logout. - accountAbnormalities.onAuthenticated(mock(), mock()) + accountAbnormalities.onAuthenticated(mockk(), mockk()) accountAbnormalities.userRequestedLogout() - verifyZeroInteractions(crashReporter) + verify { crashReporter wasNot Called } } - private fun assertCaughtException(crashReporter: CrashReporter, type: KClass) { - val captor = argumentCaptor() - verify(crashReporter).submitCaughtException(captor.capture()) - assertEquals(type, captor.value::class) + private inline fun assertCaughtException(crashReporter: CrashReporter) { + verify { + crashReporter.submitCaughtException(any()) + } } } diff --git a/app/src/test/java/org/mozilla/fenix/components/InflationAwareFeatureTest.kt b/app/src/test/java/org/mozilla/fenix/components/InflationAwareFeatureTest.kt index 5f80a8230..5e8d075cc 100644 --- a/app/src/test/java/org/mozilla/fenix/components/InflationAwareFeatureTest.kt +++ b/app/src/test/java/org/mozilla/fenix/components/InflationAwareFeatureTest.kt @@ -2,76 +2,74 @@ package org.mozilla.fenix.components import android.view.View import android.view.ViewStub +import io.mockk.mockk +import io.mockk.spyk +import io.mockk.verify import mozilla.components.support.base.feature.UserInteractionHandler import mozilla.components.support.base.feature.LifecycleAwareFeature -import mozilla.components.support.test.any -import mozilla.components.support.test.mock import org.junit.Test -import org.mockito.Mockito.never -import org.mockito.Mockito.spy -import org.mockito.Mockito.verify import java.lang.ref.WeakReference class InflationAwareFeatureTest { @Test fun `stub inflates if no feature or view exists`() { - val stub: ViewStub = mock() - val feature: InflationAwareFeature = spy(TestableInflationAwareFeature(stub)) + val stub: ViewStub = mockk(relaxed = true) + val feature: InflationAwareFeature = spyk(TestableInflationAwareFeature(stub)) feature.launch() - verify(stub).setOnInflateListener(any()) - verify(stub).inflate() + verify { stub.setOnInflateListener(any()) } + verify { stub.inflate() } } @Test fun `stub immediately launches if the feature is available`() { - val stub: ViewStub = mock() - val feature: InflationAwareFeature = spy(TestableInflationAwareFeature(stub)) + val stub: ViewStub = mockk() + val feature: InflationAwareFeature = spyk(TestableInflationAwareFeature(stub)) - feature.feature = mock() - feature.view = WeakReference(mock()) + feature.feature = mockk(relaxed = true) + feature.view = WeakReference(mockk()) feature.launch() - verify(stub, never()).setOnInflateListener(any()) - verify(stub, never()).inflate() - verify(feature).onLaunch(any(), any()) + verify(exactly = 0) { stub.setOnInflateListener(any()) } + verify(exactly = 0) { stub.inflate() } + verify { feature.onLaunch(any(), any()) } } @Test fun `feature calls stop if created`() { - val stub: ViewStub = mock() - val inflationFeature: InflationAwareFeature = spy(TestableInflationAwareFeature(stub)) - val innerFeature: LifecycleAwareFeature = mock() + val stub: ViewStub = mockk() + val inflationFeature: InflationAwareFeature = spyk(TestableInflationAwareFeature(stub)) + val innerFeature: LifecycleAwareFeature = mockk(relaxed = true) inflationFeature.stop() - verify(innerFeature, never()).stop() + verify(exactly = 0) { innerFeature.stop() } inflationFeature.feature = innerFeature inflationFeature.stop() - verify(innerFeature).stop() + verify { innerFeature.stop() } } @Test fun `start should be delegated to the inner feature`() { - val inflationFeature: InflationAwareFeature = spy(TestableInflationAwareFeature(mock())) - val innerFeature: LifecycleAwareFeature = mock() + val inflationFeature: InflationAwareFeature = spyk(TestableInflationAwareFeature(mockk())) + val innerFeature: LifecycleAwareFeature = mockk(relaxed = true) inflationFeature.feature = innerFeature inflationFeature.start() - verify(innerFeature).start() + verify { innerFeature.start() } } @Test fun `if feature has implemented UserInteractionHandler invoke it`() { - val stub: ViewStub = mock() - val inflationFeature: InflationAwareFeature = spy(TestableInflationAwareFeature(stub)) - val innerFeature: LifecycleAwareFeature = mock() + val stub: ViewStub = mockk() + val inflationFeature: InflationAwareFeature = spyk(TestableInflationAwareFeature(stub)) + val innerFeature: LifecycleAwareFeature = mockk() val userInteractionHandlerFeature = object : LifecycleAwareFeature, UserInteractionHandler { override fun onBackPressed() = true @@ -93,10 +91,7 @@ class InflationAwareFeatureTest { } class TestableInflationAwareFeature(stub: ViewStub) : InflationAwareFeature(stub) { - override fun onViewInflated(view: View): LifecycleAwareFeature { - return mock() - } + override fun onViewInflated(view: View): LifecycleAwareFeature = mockk() - override fun onLaunch(view: View, feature: LifecycleAwareFeature) { - } + override fun onLaunch(view: View, feature: LifecycleAwareFeature) = Unit } diff --git a/app/src/test/java/org/mozilla/fenix/components/TestComponents.kt b/app/src/test/java/org/mozilla/fenix/components/TestComponents.kt index 941a55599..576b67bdb 100644 --- a/app/src/test/java/org/mozilla/fenix/components/TestComponents.kt +++ b/app/src/test/java/org/mozilla/fenix/components/TestComponents.kt @@ -6,8 +6,6 @@ package org.mozilla.fenix.components import android.content.Context import io.mockk.mockk -import mozilla.components.support.test.mock -import org.mockito.Mockito.`when` import org.mozilla.fenix.utils.ClipboardHandler class TestComponents(private val context: Context) : Components(context) { @@ -28,17 +26,7 @@ class TestComponents(private val context: Context) : Components(context) { core.thumbnailStorage ) } - override val intentProcessors by lazy { - val processors: IntentProcessors = mock() - `when`(processors.externalAppIntentProcessors).thenReturn(emptyList()) - `when`(processors.privateIntentProcessor).thenReturn(mock()) - `when`(processors.intentProcessor).thenReturn(mock()) - `when`(processors.customTabIntentProcessor).thenReturn(mock()) - `when`(processors.privateCustomTabIntentProcessor).thenReturn(mock()) - `when`(processors.migrationIntentProcessor).thenReturn(mock()) - `when`(processors.fennecPageShortcutIntentProcessor).thenReturn(mock()) - processors - } + override val intentProcessors by lazy { mockk(relaxed = true) } override val analytics by lazy { Analytics(context) } override val clipboardHandler by lazy { ClipboardHandler(context) } diff --git a/app/src/test/java/org/mozilla/fenix/components/metrics/BreadcrumbRecorderTest.kt b/app/src/test/java/org/mozilla/fenix/components/metrics/BreadcrumbRecorderTest.kt index 810e8f244..ea9add329 100644 --- a/app/src/test/java/org/mozilla/fenix/components/metrics/BreadcrumbRecorderTest.kt +++ b/app/src/test/java/org/mozilla/fenix/components/metrics/BreadcrumbRecorderTest.kt @@ -6,17 +6,17 @@ package org.mozilla.fenix.components.metrics import androidx.navigation.NavController import androidx.navigation.NavDestination +import io.mockk.mockk +import io.mockk.spyk +import io.mockk.verify import mozilla.components.lib.crash.Crash import mozilla.components.lib.crash.CrashReporter import mozilla.components.lib.crash.service.CrashReporterService import mozilla.components.support.base.crash.Breadcrumb -import mozilla.components.support.test.any -import mozilla.components.support.test.mock import org.junit.Test -import org.mockito.Mockito.spy -import org.mockito.Mockito.verify internal class BreadcrumbRecorderTest { + @Test fun `ensure crash reporter recordCrashBreadcrumb is called`() { val service = object : CrashReporterService { @@ -28,9 +28,9 @@ internal class BreadcrumbRecorderTest { override fun report(crash: Crash.UncaughtExceptionCrash): String? = "" } - val reporter = spy( + val reporter = spyk( CrashReporter( - context = mock(), + context = mockk(), services = listOf(service), shouldPrompt = CrashReporter.Prompt.NEVER ) @@ -40,13 +40,13 @@ internal class BreadcrumbRecorderTest { return "test" } - val navController: NavController = mock() - val navDestination: NavDestination = mock() + val navController: NavController = mockk() + val navDestination: NavDestination = mockk() val breadCrumbRecorder = BreadcrumbsRecorder(reporter, navController, ::getBreadcrumbMessage) breadCrumbRecorder.onDestinationChanged(navController, navDestination, null) - verify(reporter).recordCrashBreadcrumb(any()) + verify { reporter.recordCrashBreadcrumb(any()) } } } diff --git a/app/src/test/java/org/mozilla/fenix/components/metrics/MetricsUtilsTest.kt b/app/src/test/java/org/mozilla/fenix/components/metrics/MetricsUtilsTest.kt index db8efc952..0ffb55261 100644 --- a/app/src/test/java/org/mozilla/fenix/components/metrics/MetricsUtilsTest.kt +++ b/app/src/test/java/org/mozilla/fenix/components/metrics/MetricsUtilsTest.kt @@ -10,24 +10,24 @@ import io.mockk.mockk import io.mockk.mockkObject import io.mockk.mockkStatic import io.mockk.slot +import io.mockk.unmockkStatic import kotlinx.coroutines.runBlocking -import org.junit.Assert import org.junit.Assert.assertEquals -import org.junit.Ignore +import org.junit.Assert.assertNull import org.junit.Test -import org.mockito.ArgumentMatchers import java.io.IOException class MetricsUtilsTest { private val context: Context = mockk(relaxed = true) - @Ignore("This test has side-effects that cause it to fail other unrelated tests.") @Test fun `getAdvertisingID() returns null if the API throws`() { + mockkStatic("com.google.android.gms.ads.identifier.AdvertisingIdClient") + val exceptions = listOf( GooglePlayServicesNotAvailableException(1), - GooglePlayServicesRepairableException(0, ArgumentMatchers.anyString(), ArgumentMatchers.any()), + GooglePlayServicesRepairableException(0, "", mockk()), IllegalStateException(), IOException() ) @@ -37,8 +37,10 @@ class MetricsUtilsTest { AdvertisingIdClient.getAdvertisingIdInfo(any()) } throws it - Assert.assertNull(MetricsUtils.getAdvertisingID(context)) + assertNull(MetricsUtils.getAdvertisingID(context)) } + + unmockkStatic("com.google.android.gms.ads.identifier.AdvertisingIdClient") } @Test @@ -46,7 +48,7 @@ class MetricsUtilsTest { mockkStatic(AdvertisingIdClient::class) every { AdvertisingIdClient.getAdvertisingIdInfo(any()) } returns null - Assert.assertNull(MetricsUtils.getAdvertisingID(context)) + assertNull(MetricsUtils.getAdvertisingID(context)) } @Test diff --git a/app/src/test/java/org/mozilla/fenix/components/searchengine/FenixSearchEngineProviderTest.kt b/app/src/test/java/org/mozilla/fenix/components/searchengine/FenixSearchEngineProviderTest.kt index 1ba6b08e0..82726fcce 100644 --- a/app/src/test/java/org/mozilla/fenix/components/searchengine/FenixSearchEngineProviderTest.kt +++ b/app/src/test/java/org/mozilla/fenix/components/searchengine/FenixSearchEngineProviderTest.kt @@ -1,7 +1,8 @@ package org.mozilla.fenix.components.searchengine import android.content.Context -import android.graphics.Bitmap +import io.mockk.every +import io.mockk.mockk import kotlinx.coroutines.CompletableDeferred import kotlinx.coroutines.Deferred import kotlinx.coroutines.ExperimentalCoroutinesApi @@ -15,8 +16,6 @@ import org.junit.Assert.assertEquals import org.junit.Before import org.junit.Test import org.junit.runner.RunWith -import org.mockito.Mockito.`when` -import org.mockito.Mockito.mock import org.mozilla.fenix.helpers.FenixRobolectricTestRunner @ExperimentalCoroutinesApi @@ -115,11 +114,10 @@ class FakeFenixSearchEngineProvider(context: Context) : FenixSearchEngineProvide id: String, n: String = id ): SearchEngine { - // Uses Mockito because of a strange Mockk error. Feel free to rewrite - return mock(SearchEngine::class.java).apply { - `when`(identifier).thenReturn(id) - `when`(name).thenReturn(n) - `when`(icon).thenReturn(mock(Bitmap::class.java)) - } + val engine = mockk() + every { engine.identifier } returns id + every { engine.name } returns n + every { engine.icon } returns mockk() + return engine } } diff --git a/app/src/test/java/org/mozilla/fenix/customtabs/ExternalAppBrowserActivityTest.kt b/app/src/test/java/org/mozilla/fenix/customtabs/ExternalAppBrowserActivityTest.kt index 06eb98c41..33393e224 100644 --- a/app/src/test/java/org/mozilla/fenix/customtabs/ExternalAppBrowserActivityTest.kt +++ b/app/src/test/java/org/mozilla/fenix/customtabs/ExternalAppBrowserActivityTest.kt @@ -9,14 +9,13 @@ import android.os.Bundle import androidx.navigation.NavDirections import io.mockk.every import io.mockk.mockk +import io.mockk.spyk +import io.mockk.verify import mozilla.components.support.utils.toSafeIntent import org.junit.Assert.assertEquals import org.junit.Assert.assertNotNull import org.junit.Assert.assertNull import org.junit.Test -import org.mockito.Mockito.never -import org.mockito.Mockito.spy -import org.mockito.Mockito.verify import org.mozilla.fenix.BrowserDirection import org.mozilla.fenix.components.metrics.Event @@ -40,7 +39,7 @@ class ExternalAppBrowserActivityTest { @Test fun `getNavDirections finishes activity if session ID is null`() { - val activity = spy(object : ExternalAppBrowserActivity() { + val activity = spyk(object : ExternalAppBrowserActivity() { public override fun getNavDirections( from: BrowserDirection, customTabSessionId: String? @@ -59,10 +58,10 @@ class ExternalAppBrowserActivityTest { var directions = activity.getNavDirections(BrowserDirection.FromGlobal, "id") assertNotNull(directions) - verify(activity, never()).finish() + verify(exactly = 0) { activity.finish() } directions = activity.getNavDirections(BrowserDirection.FromGlobal, null) assertNull(directions) - verify(activity).finish() + verify { activity.finish() } } } diff --git a/app/src/test/java/org/mozilla/fenix/customtabs/PoweredByNotificationTest.kt b/app/src/test/java/org/mozilla/fenix/customtabs/PoweredByNotificationTest.kt index f71ff95e5..f5c0f3bc6 100644 --- a/app/src/test/java/org/mozilla/fenix/customtabs/PoweredByNotificationTest.kt +++ b/app/src/test/java/org/mozilla/fenix/customtabs/PoweredByNotificationTest.kt @@ -4,12 +4,12 @@ package org.mozilla.fenix.customtabs +import io.mockk.mockk import mozilla.components.browser.state.state.BrowserState import mozilla.components.browser.state.state.CustomTabConfig import mozilla.components.browser.state.state.ExternalAppType import mozilla.components.browser.state.state.createCustomTab import mozilla.components.browser.state.store.BrowserStore -import mozilla.components.support.test.mock import mozilla.components.support.test.robolectric.testContext import org.junit.Test import org.junit.runner.RunWith @@ -50,7 +50,7 @@ class PoweredByNotificationTest { @Test fun `unregister receiver on pause`() { - val feature = PoweredByNotification(testContext, mock(), "session-id") + val feature = PoweredByNotification(testContext, mockk(), "session-id") feature.onPause() } } diff --git a/app/src/test/java/org/mozilla/fenix/downloads/DynamicDownloadDialogBehaviorTest.kt b/app/src/test/java/org/mozilla/fenix/downloads/DynamicDownloadDialogBehaviorTest.kt index e40b68875..526125006 100644 --- a/app/src/test/java/org/mozilla/fenix/downloads/DynamicDownloadDialogBehaviorTest.kt +++ b/app/src/test/java/org/mozilla/fenix/downloads/DynamicDownloadDialogBehaviorTest.kt @@ -7,16 +7,15 @@ package org.mozilla.fenix.downloads import android.animation.ValueAnimator import android.view.View import androidx.core.view.ViewCompat -import mozilla.components.support.test.mock +import io.mockk.every +import io.mockk.mockk +import io.mockk.spyk +import io.mockk.verify import mozilla.components.support.test.robolectric.testContext import org.junit.Assert.assertFalse import org.junit.Assert.assertTrue import org.junit.Test import org.junit.runner.RunWith -import org.mockito.Mockito.doReturn -import org.mockito.Mockito.spy -import org.mockito.Mockito.verify -import org.mockito.Mockito.never import org.mozilla.fenix.helpers.FenixRobolectricTestRunner @RunWith(FenixRobolectricTestRunner::class) @@ -24,24 +23,24 @@ class DynamicDownloadDialogBehaviorTest { @Test fun `Starting a nested scroll should cancel an ongoing snap animation`() { - val behavior = spy(DynamicDownloadDialogBehavior(testContext, attrs = null)) - doReturn(true).`when`(behavior).shouldScroll + val behavior = spyk(DynamicDownloadDialogBehavior(testContext, attrs = null)) + every { behavior.shouldScroll } returns true - val animator: ValueAnimator = mock() + val animator: ValueAnimator = mockk(relaxed = true) behavior.snapAnimator = animator val acceptsNestedScroll = behavior.onStartNestedScroll( - coordinatorLayout = mock(), - child = mock(), - directTargetChild = mock(), - target = mock(), + coordinatorLayout = mockk(), + child = mockk(), + directTargetChild = mockk(), + target = mockk(), axes = ViewCompat.SCROLL_AXIS_VERTICAL, type = ViewCompat.TYPE_TOUCH ) assertTrue(acceptsNestedScroll) - verify(animator).cancel() + verify { animator.cancel() } } @Test @@ -49,10 +48,10 @@ class DynamicDownloadDialogBehaviorTest { val behavior = DynamicDownloadDialogBehavior(testContext, attrs = null) val acceptsNestedScroll = behavior.onStartNestedScroll( - coordinatorLayout = mock(), - child = mock(), - directTargetChild = mock(), - target = mock(), + coordinatorLayout = mockk(), + child = mockk(), + directTargetChild = mockk(), + target = mockk(), axes = ViewCompat.SCROLL_AXIS_HORIZONTAL, type = ViewCompat.TYPE_TOUCH ) @@ -62,117 +61,123 @@ class DynamicDownloadDialogBehaviorTest { @Test fun `Behavior will snap the dialog up if it is more than 50% visible`() { - val behavior = spy(DynamicDownloadDialogBehavior(testContext, attrs = null, + val behavior = spyk(DynamicDownloadDialogBehavior(testContext, attrs = null, bottomToolbarHeight = 10f)) - doReturn(true).`when`(behavior).shouldScroll + every { behavior.shouldScroll } returns true - val animator: ValueAnimator = mock() + val animator: ValueAnimator = mockk(relaxed = true) behavior.snapAnimator = animator behavior.expanded = false - val child = mock() - doReturn(100).`when`(child)?.height - doReturn(59f).`when`(child)?.translationY + val child = mockk { + every { height } returns 100 + every { translationY } returns 59f + } behavior.onStartNestedScroll( - coordinatorLayout = mock(), + coordinatorLayout = mockk(), child = child, - directTargetChild = mock(), - target = mock(), + directTargetChild = mockk(), + target = mockk(), axes = ViewCompat.SCROLL_AXIS_VERTICAL, type = ViewCompat.TYPE_TOUCH ) assertTrue(behavior.shouldSnapAfterScroll) - verify(animator, never()).start() + verify(exactly = 0) { animator.start() } behavior.onStopNestedScroll( - coordinatorLayout = mock(), + coordinatorLayout = mockk(), child = child, - target = mock(), + target = mockk(), type = 0 ) - verify(behavior).animateSnap(child, DynamicDownloadDialogBehavior.SnapDirection.UP) + verify { behavior.animateSnap(child, DynamicDownloadDialogBehavior.SnapDirection.UP) } - verify(animator).start() + verify { animator.start() } } @Test fun `Behavior will snap the dialog down if translationY is at least equal to half the toolbarHeight`() { - val behavior = spy(DynamicDownloadDialogBehavior(testContext, attrs = null, + val behavior = spyk(DynamicDownloadDialogBehavior(testContext, attrs = null, bottomToolbarHeight = 10f)) - doReturn(true).`when`(behavior).shouldScroll + every { behavior.shouldScroll } returns true - val animator: ValueAnimator = mock() + val animator: ValueAnimator = mockk(relaxed = true) behavior.snapAnimator = animator behavior.expanded = true - val child = mock() - doReturn(100).`when`(child).height - doReturn(5f).`when`(child).translationY + val child = mockk { + every { height } returns 100 + every { translationY } returns 5f + } behavior.onStartNestedScroll( - coordinatorLayout = mock(), + coordinatorLayout = mockk(), child = child, - directTargetChild = mock(), - target = mock(), + directTargetChild = mockk(), + target = mockk(), axes = ViewCompat.SCROLL_AXIS_VERTICAL, type = ViewCompat.TYPE_TOUCH ) assertTrue(behavior.shouldSnapAfterScroll) - verify(animator, never()).start() + verify(exactly = 0) { animator.start() } behavior.onStopNestedScroll( - coordinatorLayout = mock(), + coordinatorLayout = mockk(), child = child, - target = mock(), + target = mockk(), type = 0 ) - verify(behavior).animateSnap(child, DynamicDownloadDialogBehavior.SnapDirection.DOWN) + verify { behavior.animateSnap(child, DynamicDownloadDialogBehavior.SnapDirection.DOWN) } - verify(animator).start() + verify { animator.start() } } @Test fun `Behavior will apply translation to the dialog for nested scroll`() { - val behavior = spy(DynamicDownloadDialogBehavior(testContext, attrs = null)) - doReturn(true).`when`(behavior).shouldScroll + val behavior = spyk(DynamicDownloadDialogBehavior(testContext, attrs = null)) + every { behavior.shouldScroll } returns true - val child = mock() - doReturn(100).`when`(child).height - doReturn(0f).`when`(child).translationY + val child = mockk { + every { height } returns 100 + every { translationY } returns 0f + every { translationY = any() } returns Unit + } behavior.onNestedPreScroll( - coordinatorLayout = mock(), + coordinatorLayout = mockk(), child = child, - target = mock(), + target = mockk(), dx = 0, dy = 25, consumed = IntArray(0), type = 0 ) - verify(child).translationY = 25f + verify { child.translationY = 25f } } @Test fun `Behavior will animateSnap UP when forceExpand is called`() { - val behavior = spy(DynamicDownloadDialogBehavior(testContext, attrs = null)) - val dynamicDialogView: View = mock() - doReturn(true).`when`(behavior).shouldScroll + val behavior = spyk(DynamicDownloadDialogBehavior(testContext, attrs = null)) + val dynamicDialogView: View = mockk(relaxed = true) + every { behavior.shouldScroll } returns true behavior.forceExpand(dynamicDialogView) - verify(behavior).animateSnap( - dynamicDialogView, - DynamicDownloadDialogBehavior.SnapDirection.UP - ) + verify { + behavior.animateSnap( + dynamicDialogView, + DynamicDownloadDialogBehavior.SnapDirection.UP + ) + } } } diff --git a/app/src/test/java/org/mozilla/fenix/ext/SessionTest.kt b/app/src/test/java/org/mozilla/fenix/ext/SessionTest.kt index 0e8424edb..d784e257c 100644 --- a/app/src/test/java/org/mozilla/fenix/ext/SessionTest.kt +++ b/app/src/test/java/org/mozilla/fenix/ext/SessionTest.kt @@ -4,12 +4,13 @@ package org.mozilla.fenix.ext +import io.mockk.mockk import mozilla.components.browser.session.Session import mozilla.components.browser.state.state.BrowserState import mozilla.components.browser.state.state.ReaderState import mozilla.components.browser.state.state.createTab import mozilla.components.browser.state.store.BrowserStore -import mozilla.components.support.test.mock +import mozilla.components.lib.publicsuffixlist.PublicSuffixList import org.junit.Assert.assertEquals import org.junit.Test import org.junit.runner.RunWith @@ -36,8 +37,9 @@ class SessionTest { val tabs = listOf(tabWithoutReaderState, tabWithInactiveReaderState, tabWithActiveReaderState) val store = BrowserStore(BrowserState(tabs)) - assertEquals(sessionWithoutReaderState.url, sessionWithoutReaderState.toTab(store, mock()).url) - assertEquals(sessionWithInactiveReaderState.url, sessionWithInactiveReaderState.toTab(store, mock()).url) - assertEquals("https://blog.mozilla.org/123", sessionWithActiveReaderState.toTab(store, mock()).url) + val suffixList = mockk(relaxed = true) + assertEquals(sessionWithoutReaderState.url, sessionWithoutReaderState.toTab(store, suffixList).url) + assertEquals(sessionWithInactiveReaderState.url, sessionWithInactiveReaderState.toTab(store, suffixList).url) + assertEquals("https://blog.mozilla.org/123", sessionWithActiveReaderState.toTab(store, suffixList).url) } } diff --git a/app/src/test/java/org/mozilla/fenix/ext/TabCollectionTest.kt b/app/src/test/java/org/mozilla/fenix/ext/TabCollectionTest.kt index 58c95f5bf..f7532123d 100644 --- a/app/src/test/java/org/mozilla/fenix/ext/TabCollectionTest.kt +++ b/app/src/test/java/org/mozilla/fenix/ext/TabCollectionTest.kt @@ -5,14 +5,14 @@ package org.mozilla.fenix.ext import androidx.core.content.ContextCompat +import io.mockk.every +import io.mockk.mockk import mozilla.components.feature.tab.collections.TabCollection -import mozilla.components.support.test.mock import mozilla.components.support.test.robolectric.testContext import org.junit.Assert.assertEquals import org.junit.Assert.assertNotEquals import org.junit.Test import org.junit.runner.RunWith -import org.mockito.Mockito.`when` import org.mozilla.fenix.R import org.mozilla.fenix.helpers.FenixRobolectricTestRunner @@ -33,8 +33,8 @@ class TabCollectionTest { } private fun mockTabCollection(id: Long): TabCollection { - val collection: TabCollection = mock() - `when`(collection.id).thenReturn(id) + val collection: TabCollection = mockk() + every { collection.id } returns id return collection } } diff --git a/app/src/test/java/org/mozilla/fenix/home/intent/SpeechProcessingIntentProcessorTest.kt b/app/src/test/java/org/mozilla/fenix/home/intent/SpeechProcessingIntentProcessorTest.kt index c98eb68e3..7e58c1570 100644 --- a/app/src/test/java/org/mozilla/fenix/home/intent/SpeechProcessingIntentProcessorTest.kt +++ b/app/src/test/java/org/mozilla/fenix/home/intent/SpeechProcessingIntentProcessorTest.kt @@ -10,14 +10,16 @@ import io.mockk.Called import io.mockk.every import io.mockk.mockk import io.mockk.verify +import mozilla.components.browser.search.SearchEngine +import org.junit.Before import org.junit.Test import org.junit.runner.RunWith import org.mozilla.fenix.BrowserDirection import org.mozilla.fenix.HomeActivity import org.mozilla.fenix.components.metrics.MetricController import org.mozilla.fenix.ext.components -import org.mozilla.fenix.widget.VoiceSearchActivity.Companion.SPEECH_PROCESSING import org.mozilla.fenix.helpers.FenixRobolectricTestRunner +import org.mozilla.fenix.widget.VoiceSearchActivity.Companion.SPEECH_PROCESSING @RunWith(FenixRobolectricTestRunner::class) class SpeechProcessingIntentProcessorTest { @@ -27,6 +29,13 @@ class SpeechProcessingIntentProcessorTest { private val out: Intent = mockk(relaxed = true) private val metrics: MetricController = mockk(relaxed = true) + @Before + fun setup() { + val searchEngine = mockk(relaxed = true) + every { activity.components.search.searchEngineManager.defaultSearchEngine } returns searchEngine + every { activity.components.search.provider.getDefaultEngine(activity) } returns searchEngine + } + @Test fun `do not process blank intents`() { val processor = SpeechProcessingIntentProcessor(activity, metrics) @@ -58,7 +67,6 @@ class SpeechProcessingIntentProcessorTest { putExtra(HomeActivity.OPEN_TO_BROWSER_AND_LOAD, true) } val processor = SpeechProcessingIntentProcessor(activity, metrics) - every { activity.components.search.provider.getDefaultEngine(activity) } returns mockk(relaxed = true) processor.process(intent, navController, out) @@ -81,7 +89,6 @@ class SpeechProcessingIntentProcessorTest { putExtra(SPEECH_PROCESSING, "hello world") } val processor = SpeechProcessingIntentProcessor(activity, metrics) - every { activity.components.search.provider.getDefaultEngine(activity) } returns mockk(relaxed = true) processor.process(intent, mockk(), mockk(relaxed = true)) diff --git a/app/src/test/java/org/mozilla/fenix/library/history/HistoryControllerTest.kt b/app/src/test/java/org/mozilla/fenix/library/history/HistoryControllerTest.kt index ff837a3ee..c0372e3c4 100644 --- a/app/src/test/java/org/mozilla/fenix/library/history/HistoryControllerTest.kt +++ b/app/src/test/java/org/mozilla/fenix/library/history/HistoryControllerTest.kt @@ -20,6 +20,7 @@ import org.junit.Assert.assertTrue import org.junit.Before import org.junit.Test import org.junit.runner.RunWith +import org.mozilla.fenix.R import org.mozilla.fenix.browser.browsingmode.BrowsingMode import org.mozilla.fenix.components.FenixSnackbar import org.mozilla.fenix.helpers.FenixRobolectricTestRunner @@ -182,8 +183,8 @@ class HistoryControllerTest { } assertEquals( - directions.captured::class.simpleName, - "ActionGlobalShareFragment" + directions.captured.actionId, + R.id.action_global_shareFragment ) assertEquals(1, (directions.captured.arguments["data"] as Array).size) assertEquals(historyItem.title, (directions.captured.arguments["data"] as Array)[0].title) diff --git a/app/src/test/java/org/mozilla/fenix/settings/advanced/LocaleSettingsControllerTest.kt b/app/src/test/java/org/mozilla/fenix/settings/advanced/LocaleSettingsControllerTest.kt index ebe78b5a6..8923f5e2a 100644 --- a/app/src/test/java/org/mozilla/fenix/settings/advanced/LocaleSettingsControllerTest.kt +++ b/app/src/test/java/org/mozilla/fenix/settings/advanced/LocaleSettingsControllerTest.kt @@ -14,7 +14,6 @@ import io.mockk.mockkObject import io.mockk.mockkStatic import io.mockk.verify import mozilla.components.support.locale.LocaleManager -import mozilla.components.support.test.mock import org.junit.Before import org.junit.Test import java.util.Locale @@ -61,7 +60,7 @@ class LocaleSettingsControllerTest { @Test fun `set a new locale from the list`() { val selectedLocale = Locale("en", "UK") - val otherLocale: Locale = mock() + val otherLocale: Locale = mockk() every { localeSettingsStore.state } returns LocaleSettingsState( mockk(), mockk(), diff --git a/app/src/test/java/org/mozilla/fenix/share/ShareViewModelTest.kt b/app/src/test/java/org/mozilla/fenix/share/ShareViewModelTest.kt index 79875562a..17502d251 100644 --- a/app/src/test/java/org/mozilla/fenix/share/ShareViewModelTest.kt +++ b/app/src/test/java/org/mozilla/fenix/share/ShareViewModelTest.kt @@ -11,6 +11,7 @@ import android.content.pm.ResolveInfo import android.graphics.drawable.Drawable import android.net.ConnectivityManager import androidx.core.content.getSystemService +import androidx.lifecycle.asFlow import io.mockk.Runs import io.mockk.every import io.mockk.just @@ -18,8 +19,8 @@ import io.mockk.mockk import io.mockk.mockkStatic import io.mockk.spyk import io.mockk.verify -import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.first import kotlinx.coroutines.test.TestCoroutineDispatcher import kotlinx.coroutines.test.runBlockingTest import mozilla.components.feature.share.RecentApp @@ -33,21 +34,23 @@ import org.junit.runner.RunWith import org.mozilla.fenix.ext.application import org.mozilla.fenix.ext.components import org.mozilla.fenix.ext.isOnline +import org.mozilla.fenix.helpers.FenixRobolectricTestRunner import org.mozilla.fenix.share.ShareViewModel.Companion.RECENT_APPS_LIMIT import org.mozilla.fenix.share.listadapters.AppShareOption import org.mozilla.fenix.share.listadapters.SyncShareOption -import org.mozilla.fenix.helpers.FenixRobolectricTestRunner @RunWith(FenixRobolectricTestRunner::class) @ExperimentalCoroutinesApi class ShareViewModelTest { private val packageName = "org.mozilla.fenix" + private val testIoDispatcher = TestCoroutineDispatcher() private lateinit var application: Application private lateinit var packageManager: PackageManager private lateinit var connectivityManager: ConnectivityManager private lateinit var fxaAccountManager: FxaAccountManager private lateinit var viewModel: ShareViewModel + private lateinit var storage: RecentAppsStorage @Before fun setup() { @@ -55,6 +58,7 @@ class ShareViewModelTest { packageManager = mockk(relaxed = true) connectivityManager = mockk(relaxed = true) fxaAccountManager = mockk(relaxed = true) + storage = mockk(relaxUnitFun = true) mockkStatic("org.mozilla.fenix.ext.ConnectivityManagerKt") @@ -63,7 +67,8 @@ class ShareViewModelTest { every { application.getSystemService() } returns connectivityManager every { application.components.backgroundServices.accountManager } returns fxaAccountManager - viewModel = ShareViewModel(application) + viewModel = spyk(ShareViewModel(application)) + viewModel.ioDispatcher = testIoDispatcher } @Test @@ -73,28 +78,20 @@ class ShareViewModelTest { } @Test - fun `loadDevicesAndApps`() = runBlockingTest { - mockkStatic(Dispatchers::class) - every { - Dispatchers.IO - } returns TestCoroutineDispatcher() - viewModel = spyk(viewModel) - val drawable: Drawable = mockk() - val appOptions = ArrayList() - val appElement = AppShareOption("Label", drawable, "Package", "Activity") - appOptions.add(appElement) - - val recentAppOptions = ArrayList() - val appEntity: RecentApp = mockk() - every { appEntity.activityName } returns "Activity" - recentAppOptions.add(appEntity) - val storage: RecentAppsStorage = mockk(relaxed = true) - viewModel.recentAppsStorage = storage + fun `test loadDevicesAndApps`() = runBlockingTest { + val appOptions = listOf( + AppShareOption("Label", mockk(), "Package", "Activity") + ) - every { viewModel.buildAppsList(any(), any()) } returns appOptions + val appEntity = mockk() + every { appEntity.activityName } returns "Activity" + val recentAppOptions = listOf(appEntity) every { storage.updateDatabaseWithNewApps(appOptions.map { app -> app.packageName }) } just Runs every { storage.getRecentAppsUpTo(RECENT_APPS_LIMIT) } returns recentAppOptions + every { viewModel.buildAppsList(any(), any()) } returns appOptions + viewModel.recentAppsStorage = storage + viewModel.loadDevicesAndApps() verify { @@ -103,8 +100,8 @@ class ShareViewModelTest { any() ) } - assertEquals(1, viewModel.recentAppsList.value?.size) - assertEquals(0, viewModel.appsList.value?.size) + assertEquals(1, viewModel.recentAppsList.asFlow().first().size) + assertEquals(0, viewModel.appsList.asFlow().first().size) } @Test diff --git a/app/src/test/java/org/mozilla/fenix/tabtray/TabTrayViewHolderTest.kt b/app/src/test/java/org/mozilla/fenix/tabtray/TabTrayViewHolderTest.kt index 7a8708519..a8daf1f1c 100644 --- a/app/src/test/java/org/mozilla/fenix/tabtray/TabTrayViewHolderTest.kt +++ b/app/src/test/java/org/mozilla/fenix/tabtray/TabTrayViewHolderTest.kt @@ -6,14 +6,16 @@ package org.mozilla.fenix.tabtray import android.view.LayoutInflater import androidx.test.core.app.ApplicationProvider +import io.mockk.Runs +import io.mockk.every +import io.mockk.just import io.mockk.mockk +import io.mockk.spyk import mozilla.components.browser.toolbar.MAX_URI_LENGTH import mozilla.components.concept.tabstray.Tab import org.junit.Assert.assertEquals import org.junit.Test import org.junit.runner.RunWith -import org.mockito.Mockito.doNothing -import org.mockito.Mockito.spy import org.mozilla.fenix.R import org.mozilla.fenix.helpers.FenixRobolectricTestRunner @@ -25,8 +27,8 @@ class TabTrayViewHolderTest { val view = LayoutInflater.from(ApplicationProvider.getApplicationContext()).inflate( R.layout.tab_tray_item, null, false) - val tabViewHolder = spy(TabTrayViewHolder(view) { null }) - doNothing().`when`(tabViewHolder).updateBackgroundColor(false) + val tabViewHolder = spyk(TabTrayViewHolder(view) { null }) + every { tabViewHolder.updateBackgroundColor(false) } just Runs val extremelyLongUrl = "m".repeat(MAX_URI_LENGTH + 1) val tab = Tab( diff --git a/buildSrc/src/main/java/Dependencies.kt b/buildSrc/src/main/java/Dependencies.kt index dfe6d65f1..c91feb687 100644 --- a/buildSrc/src/main/java/Dependencies.kt +++ b/buildSrc/src/main/java/Dependencies.kt @@ -37,7 +37,6 @@ object Versions { const val installreferrer = "1.0" const val junit = "5.5.2" - const val mockito = "2.24.5" const val mockk = "1.10.0" const val mockwebserver = "3.11.0" @@ -176,8 +175,6 @@ object Deps { const val installreferrer = "com.android.installreferrer:installreferrer:${Versions.installreferrer}" const val junit = "junit:junit:${Versions.junit}" - const val mockito_core = "org.mockito:mockito-core:${Versions.mockito}" - const val mockito_android = "org.mockito:mockito-android:${Versions.mockito}" const val mockk = "io.mockk:mockk:${Versions.mockk}" // --- START AndroidX test dependencies --- //