2
0
mirror of https://github.com/fork-maintainers/iceraven-browser synced 2024-11-17 15:26:23 +00:00

[fenix] Remove Mockito

This commit is contained in:
Tiger Oakes 2020-05-28 17:43:40 -07:00 committed by Emily Kager
parent fd193e05f1
commit 110771d077
21 changed files with 286 additions and 288 deletions

View File

@ -593,8 +593,6 @@ dependencies {
testImplementation 'org.apache.maven:maven-ant-tasks:2.1.3' testImplementation 'org.apache.maven:maven-ant-tasks:2.1.3'
implementation Deps.mozilla_support_rusthttp implementation Deps.mozilla_support_rusthttp
testImplementation Deps.mockito_core
androidTestImplementation Deps.mockito_android
testImplementation Deps.mockk testImplementation Deps.mockk
// For the initial release of Glean 19, we require consumer applications to // For the initial release of Glean 19, we require consumer applications to

View File

@ -32,7 +32,7 @@ class IntentReceiverActivity : Activity() {
// The intent property is nullable, but the rest of the code below // 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 // assumes it is not. If it's null, then we make a new one and open
// the HomeActivity. // the HomeActivity.
val intent = intent?.let { Intent(intent) } ?: Intent() val intent = intent?.let { Intent(it) } ?: Intent()
intent.stripUnwantedFlags() intent.stripUnwantedFlags()
processIntent(intent) processIntent(intent)
} }

View File

@ -18,7 +18,7 @@ import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.LiveData import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.Dispatchers.IO import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import mozilla.components.concept.sync.DeviceCapability import mozilla.components.concept.sync.DeviceCapability
import mozilla.components.feature.share.RecentAppsStorage import mozilla.components.feature.share.RecentAppsStorage
@ -38,6 +38,8 @@ class ShareViewModel(application: Application) : AndroidViewModel(application) {
private val fxaAccountManager = application.components.backgroundServices.accountManager private val fxaAccountManager = application.components.backgroundServices.accountManager
@VisibleForTesting @VisibleForTesting
internal var recentAppsStorage = RecentAppsStorage(application.applicationContext) internal var recentAppsStorage = RecentAppsStorage(application.applicationContext)
@VisibleForTesting
internal var ioDispatcher = Dispatchers.IO
private val devicesListLiveData = MutableLiveData<List<SyncShareOption>>(emptyList()) private val devicesListLiveData = MutableLiveData<List<SyncShareOption>>(emptyList())
private val appsListLiveData = MutableLiveData<List<AppShareOption>>(emptyList()) private val appsListLiveData = MutableLiveData<List<AppShareOption>>(emptyList())
@ -49,7 +51,7 @@ class ShareViewModel(application: Application) : AndroidViewModel(application) {
override fun onAvailable(network: Network?) = reloadDevices(network) override fun onAvailable(network: Network?) = reloadDevices(network)
private fun reloadDevices(network: Network?) { private fun reloadDevices(network: Network?) {
viewModelScope.launch(IO) { viewModelScope.launch(ioDispatcher) {
fxaAccountManager.authenticatedAccount() fxaAccountManager.authenticatedAccount()
?.deviceConstellation() ?.deviceConstellation()
?.refreshDevicesAsync() ?.refreshDevicesAsync()
@ -83,7 +85,7 @@ class ShareViewModel(application: Application) : AndroidViewModel(application) {
connectivityManager?.registerNetworkCallback(networkRequest, networkCallback) connectivityManager?.registerNetworkCallback(networkRequest, networkCallback)
// Start preparing the data as soon as we have a valid Context // 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 { val shareIntent = Intent(Intent.ACTION_SEND).apply {
type = "text/plain" type = "text/plain"
flags = Intent.FLAG_ACTIVITY_NEW_TASK flags = Intent.FLAG_ACTIVITY_NEW_TASK
@ -98,7 +100,7 @@ class ShareViewModel(application: Application) : AndroidViewModel(application) {
appsListLiveData.postValue(apps) appsListLiveData.postValue(apps)
} }
viewModelScope.launch(IO) { viewModelScope.launch(ioDispatcher) {
val devices = buildDeviceList(fxaAccountManager) val devices = buildDeviceList(fxaAccountManager)
devicesListLiveData.postValue(devices) devicesListLiveData.postValue(devices)
} }

View File

@ -4,42 +4,63 @@
package org.mozilla.fenix package org.mozilla.fenix
import android.app.Activity
import android.content.Intent import android.content.Intent
import android.content.Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY 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.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.runBlockingTest 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.assertEquals
import org.junit.Assert.assertTrue import org.junit.Assert.assertTrue
import org.junit.Before
import org.junit.Test import org.junit.Test
import org.junit.runner.RunWith import org.junit.runner.RunWith
import org.mockito.Mockito.`when` import org.mozilla.fenix.components.IntentProcessors
import org.mockito.Mockito.never
import org.mockito.Mockito.verify
import org.mozilla.fenix.customtabs.ExternalAppBrowserActivity import org.mozilla.fenix.customtabs.ExternalAppBrowserActivity
import org.mozilla.fenix.ext.components import org.mozilla.fenix.ext.components
import org.mozilla.fenix.ext.settings import org.mozilla.fenix.ext.settings
import org.mozilla.fenix.shortcut.NewTabShortcutIntentProcessor
import org.robolectric.Robolectric
import org.mozilla.fenix.helpers.FenixRobolectricTestRunner import org.mozilla.fenix.helpers.FenixRobolectricTestRunner
import org.mozilla.fenix.shortcut.NewTabShortcutIntentProcessor
import org.mozilla.fenix.utils.Settings
import org.robolectric.Robolectric
import org.robolectric.Shadows.shadowOf import org.robolectric.Shadows.shadowOf
@ExperimentalCoroutinesApi @ExperimentalCoroutinesApi
@RunWith(FenixRobolectricTestRunner::class) @RunWith(FenixRobolectricTestRunner::class)
class IntentReceiverActivityTest { 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 @Test
fun `process intent with flag launched from history`() = runBlockingTest { fun `process intent with flag launched from history`() = runBlockingTest {
testContext.settings().openLinksInAPrivateTab = false
val intent = Intent() val intent = Intent()
intent.flags = FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY 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() val activity = Robolectric.buildActivity(IntentReceiverActivity::class.java, intent).get()
attachMocks(activity)
activity.processIntent(intent) activity.processIntent(intent)
val shadow = shadowOf(activity) val shadow = shadowOf(activity)
@ -51,16 +72,13 @@ class IntentReceiverActivityTest {
@Test @Test
fun `process intent with action OPEN_PRIVATE_TAB`() = runBlockingTest { fun `process intent with action OPEN_PRIVATE_TAB`() = runBlockingTest {
testContext.settings().openLinksInAPrivateTab = false
val intent = Intent() val intent = Intent()
intent.action = NewTabShortcutIntentProcessor.ACTION_OPEN_PRIVATE_TAB intent.action = NewTabShortcutIntentProcessor.ACTION_OPEN_PRIVATE_TAB
`when`(testContext.components.intentProcessors.migrationIntentProcessor.process(intent)).thenReturn(false) coEvery { intentProcessors.intentProcessor.process(intent) } returns false
`when`(testContext.components.intentProcessors.intentProcessor.process(intent)).thenReturn(false) coEvery { intentProcessors.customTabIntentProcessor.process(intent) } returns 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() val activity = Robolectric.buildActivity(IntentReceiverActivity::class.java, intent).get()
attachMocks(activity)
activity.processIntent(intent) activity.processIntent(intent)
val shadow = shadowOf(activity) val shadow = shadowOf(activity)
@ -73,16 +91,11 @@ class IntentReceiverActivityTest {
@Test @Test
fun `process intent with action OPEN_TAB`() = runBlockingTest { fun `process intent with action OPEN_TAB`() = runBlockingTest {
testContext.settings().openLinksInAPrivateTab = false
val intent = Intent() val intent = Intent()
intent.action = NewTabShortcutIntentProcessor.ACTION_OPEN_TAB 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() val activity = Robolectric.buildActivity(IntentReceiverActivity::class.java, intent).get()
attachMocks(activity)
activity.processIntent(intent) activity.processIntent(intent)
val shadow = shadowOf(activity) val shadow = shadowOf(activity)
@ -90,19 +103,13 @@ class IntentReceiverActivityTest {
assertEquals(HomeActivity::class.java.name, actualIntent.component?.className) assertEquals(HomeActivity::class.java.name, actualIntent.component?.className)
assertEquals(false, actualIntent.getBooleanExtra(HomeActivity.PRIVATE_BROWSING_MODE, false)) assertEquals(false, actualIntent.getBooleanExtra(HomeActivity.PRIVATE_BROWSING_MODE, false))
assertEquals(false, actualIntent.getBooleanExtra(HomeActivity.OPEN_TO_BROWSER, true))
} }
@Test @Test
fun `process intent starts Activity`() = runBlockingTest { fun `process intent starts Activity`() = runBlockingTest {
testContext.settings().openLinksInAPrivateTab = false
val intent = Intent() 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() val activity = Robolectric.buildActivity(IntentReceiverActivity::class.java, intent).get()
attachMocks(activity)
activity.processIntent(intent) activity.processIntent(intent)
val shadow = shadowOf(activity) val shadow = shadowOf(activity)
@ -114,57 +121,45 @@ class IntentReceiverActivityTest {
@Test @Test
fun `process intent with launchLinksInPrivateTab set to true`() = runBlockingTest { 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() 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() val activity = Robolectric.buildActivity(IntentReceiverActivity::class.java, intent).get()
attachMocks(activity)
activity.processIntent(intent) activity.processIntent(intent)
// Not using mockk here because process is a suspend function val normalProcessor = intentProcessors.intentProcessor
// and mockito makes this easier to read. coVerify(exactly = 0) { normalProcessor.process(intent) }
verify(testContext.components.intentProcessors.intentProcessor, never()).process(intent) coVerify { intentProcessors.privateIntentProcessor.process(intent) }
verify(testContext.components.intentProcessors.privateIntentProcessor).process(intent)
} }
@Test @Test
fun `process intent with launchLinksInPrivateTab set to false`() = runBlockingTest { fun `process intent with launchLinksInPrivateTab set to false`() = runBlockingTest {
testContext.settings().openLinksInAPrivateTab = false
val intent = Intent() 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() val activity = Robolectric.buildActivity(IntentReceiverActivity::class.java, intent).get()
attachMocks(activity)
activity.processIntent(intent) activity.processIntent(intent)
// Not using mockk here because process is a suspend function coVerify(exactly = 0) { intentProcessors.privateIntentProcessor.process(intent) }
// and mockito makes this easier to read. coVerify { intentProcessors.intentProcessor.process(intent) }
verify(testContext.components.intentProcessors.privateIntentProcessor, never()).process(intent)
verify(testContext.components.intentProcessors.intentProcessor).process(intent)
} }
@Test @Test
fun `process custom tab intent`() = runBlockingTest { fun `process custom tab intent`() = runBlockingTest {
testContext.settings().openLinksInAPrivateTab = false
val intent = Intent() val intent = Intent()
`when`(testContext.components.intentProcessors.migrationIntentProcessor.process(intent)).thenReturn(false) coEvery { intentProcessors.intentProcessor.process(intent) } returns false
`when`(testContext.components.intentProcessors.fennecPageShortcutIntentProcessor.process(intent)).thenReturn(false) coEvery { intentProcessors.customTabIntentProcessor.process(intent) } returns true
`when`(testContext.components.intentProcessors.customTabIntentProcessor.process(intent)).thenReturn(true)
val activity = Robolectric.buildActivity(IntentReceiverActivity::class.java, intent).get() val activity = Robolectric.buildActivity(IntentReceiverActivity::class.java, intent).get()
attachMocks(activity)
activity.processIntent(intent) activity.processIntent(intent)
// Not using mockk here because process is a suspend function coVerify(exactly = 0) { intentProcessors.privateCustomTabIntentProcessor.process(intent) }
// and mockito makes this easier to read. coVerify { intentProcessors.customTabIntentProcessor.process(intent) }
verify(testContext.components.intentProcessors.privateIntentProcessor, never()).process(intent)
verify(testContext.components.intentProcessors.customTabIntentProcessor).process(intent)
assertEquals(ExternalAppBrowserActivity::class.java.name, intent.component!!.className) assertEquals(ExternalAppBrowserActivity::class.java.name, intent.component!!.className)
assertTrue(intent.getBooleanExtra(HomeActivity.OPEN_TO_BROWSER, false)) assertTrue(intent.getBooleanExtra(HomeActivity.OPEN_TO_BROWSER, false))
@ -172,22 +167,33 @@ class IntentReceiverActivityTest {
@Test @Test
fun `process private custom tab intent`() = runBlockingTest { fun `process private custom tab intent`() = runBlockingTest {
testContext.settings().openLinksInAPrivateTab = true every { settings.openLinksInAPrivateTab } returns true
val intent = Intent() val intent = Intent()
`when`(testContext.components.intentProcessors.migrationIntentProcessor.process(intent)).thenReturn(false) coEvery { intentProcessors.privateCustomTabIntentProcessor.process(intent) } returns true
`when`(testContext.components.intentProcessors.privateCustomTabIntentProcessor.process(intent)).thenReturn(true)
`when`(testContext.components.intentProcessors.fennecPageShortcutIntentProcessor.process(intent)).thenReturn(false)
val activity = Robolectric.buildActivity(IntentReceiverActivity::class.java, intent).get() val activity = Robolectric.buildActivity(IntentReceiverActivity::class.java, intent).get()
attachMocks(activity)
activity.processIntent(intent) activity.processIntent(intent)
// Not using mockk here because process is a suspend function val normalProcessor = intentProcessors.customTabIntentProcessor
// and mockito makes this easier to read. coVerify(exactly = 0) { normalProcessor.process(intent) }
verify(testContext.components.intentProcessors.intentProcessor, never()).process(intent) coVerify { intentProcessors.privateCustomTabIntentProcessor.process(intent) }
verify(testContext.components.intentProcessors.privateCustomTabIntentProcessor).process(intent)
assertEquals(ExternalAppBrowserActivity::class.java.name, intent.component!!.className) assertEquals(ExternalAppBrowserActivity::class.java.name, intent.component!!.className)
assertTrue(intent.getBooleanExtra(HomeActivity.OPEN_TO_BROWSER, false)) 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 <reified T : IntentProcessor> mockIntentProcessor(): T {
return mockk {
coEvery { process(any()) } returns false
}
}
} }

View File

@ -4,27 +4,26 @@
package org.mozilla.fenix.components 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 org.mozilla.fenix.helpers.FenixRobolectricTestRunner
import kotlinx.coroutines.CompletableDeferred import kotlinx.coroutines.CompletableDeferred
import kotlinx.coroutines.runBlocking import kotlinx.coroutines.runBlocking
import mozilla.components.lib.crash.CrashReporter import mozilla.components.lib.crash.CrashReporter
import mozilla.components.service.fxa.manager.FxaAccountManager 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 mozilla.components.support.test.robolectric.testContext
import org.junit.Assert.assertEquals import org.junit.Assert.assertEquals
import org.junit.Assert.fail import org.junit.Assert.fail
import org.junit.Test import org.junit.Test
import org.junit.runner.RunWith import org.junit.runner.RunWith
import org.mockito.Mockito.verifyZeroInteractions
import org.mockito.Mockito.verify
import kotlin.reflect.KClass
@RunWith(FenixRobolectricTestRunner::class) @RunWith(FenixRobolectricTestRunner::class)
class AccountAbnormalitiesTest { class AccountAbnormalitiesTest {
@Test @Test
fun `account manager must be configured`() { fun `account manager must be configured`() {
val crashReporter: CrashReporter = mock() val crashReporter: CrashReporter = mockk()
// no account present // no account present
val accountAbnormalities = AccountAbnormalities(testContext, crashReporter) val accountAbnormalities = AccountAbnormalities(testContext, crashReporter)
@ -37,7 +36,7 @@ class AccountAbnormalitiesTest {
} }
try { try {
accountAbnormalities.onAuthenticated(mock(), mock()) accountAbnormalities.onAuthenticated(mockk(), mockk())
fail() fail()
} catch (e: IllegalStateException) { } catch (e: IllegalStateException) {
assertEquals("onAuthenticated before account manager was configured", e.message) assertEquals("onAuthenticated before account manager was configured", e.message)
@ -50,13 +49,13 @@ class AccountAbnormalitiesTest {
assertEquals("onLoggedOut before account manager was configured", e.message) assertEquals("onLoggedOut before account manager was configured", e.message)
} }
verifyZeroInteractions(crashReporter) verify { crashReporter wasNot Called }
} }
@Test @Test
fun `LogoutWithoutAuth detected`() = runBlocking { fun `LogoutWithoutAuth detected`() = runBlocking {
val crashReporter: CrashReporter = mock() val crashReporter: CrashReporter = mockk(relaxed = true)
val accountManager: FxaAccountManager = mock() val accountManager: FxaAccountManager = mockk(relaxed = true)
val accountAbnormalities = AccountAbnormalities(testContext, crashReporter, this.coroutineContext) val accountAbnormalities = AccountAbnormalities(testContext, crashReporter, this.coroutineContext)
accountAbnormalities.accountManagerInitializedAsync( accountAbnormalities.accountManagerInitializedAsync(
@ -66,13 +65,13 @@ class AccountAbnormalitiesTest {
// Logout action must be preceded by auth. // Logout action must be preceded by auth.
accountAbnormalities.userRequestedLogout() accountAbnormalities.userRequestedLogout()
assertCaughtException(crashReporter, AbnormalFxaEvent.LogoutWithoutAuth::class) assertCaughtException<AbnormalFxaEvent.LogoutWithoutAuth>(crashReporter)
} }
@Test @Test
fun `OverlappingFxaLogoutRequest detected`() = runBlocking { fun `OverlappingFxaLogoutRequest detected`() = runBlocking {
val crashReporter: CrashReporter = mock() val crashReporter: CrashReporter = mockk(relaxed = true)
val accountManager: FxaAccountManager = mock() val accountManager: FxaAccountManager = mockk(relaxed = true)
val accountAbnormalities = AccountAbnormalities(testContext, crashReporter, this.coroutineContext) val accountAbnormalities = AccountAbnormalities(testContext, crashReporter, this.coroutineContext)
accountAbnormalities.accountManagerInitializedAsync( accountAbnormalities.accountManagerInitializedAsync(
@ -80,20 +79,20 @@ class AccountAbnormalitiesTest {
CompletableDeferred(Unit).also { it.complete(Unit) } CompletableDeferred(Unit).also { it.complete(Unit) }
).await() ).await()
accountAbnormalities.onAuthenticated(mock(), mock()) accountAbnormalities.onAuthenticated(mockk(), mockk())
// So far, so good. A regular logout request while being authenticated. // So far, so good. A regular logout request while being authenticated.
accountAbnormalities.userRequestedLogout() accountAbnormalities.userRequestedLogout()
verifyZeroInteractions(crashReporter) verify { crashReporter wasNot Called }
// We never saw a logout callback after previous logout request, so this is an overlapping request. // We never saw a logout callback after previous logout request, so this is an overlapping request.
accountAbnormalities.userRequestedLogout() accountAbnormalities.userRequestedLogout()
assertCaughtException(crashReporter, AbnormalFxaEvent.OverlappingFxaLogoutRequest::class) assertCaughtException<AbnormalFxaEvent.OverlappingFxaLogoutRequest>(crashReporter)
} }
@Test @Test
fun `callback logout abnormalities detected`() = runBlocking { fun `callback logout abnormalities detected`() = runBlocking {
val crashReporter: CrashReporter = mock() val crashReporter: CrashReporter = mockk(relaxed = true)
val accountManager: FxaAccountManager = mock() val accountManager: FxaAccountManager = mockk(relaxed = true)
val accountAbnormalities = AccountAbnormalities(testContext, crashReporter, this.coroutineContext) val accountAbnormalities = AccountAbnormalities(testContext, crashReporter, this.coroutineContext)
accountAbnormalities.accountManagerInitializedAsync( accountAbnormalities.accountManagerInitializedAsync(
@ -103,13 +102,13 @@ class AccountAbnormalitiesTest {
// User didn't request this logout. // User didn't request this logout.
accountAbnormalities.onLoggedOut() accountAbnormalities.onLoggedOut()
assertCaughtException(crashReporter, AbnormalFxaEvent.UnexpectedFxaLogout::class) assertCaughtException<AbnormalFxaEvent.UnexpectedFxaLogout>(crashReporter)
} }
@Test @Test
fun `login happy case + disappearing account detected`() = runBlocking { fun `login happy case + disappearing account detected`() = runBlocking {
val crashReporter: CrashReporter = mock() val crashReporter: CrashReporter = mockk(relaxed = true)
val accountManager: FxaAccountManager = mock() val accountManager: FxaAccountManager = mockk(relaxed = true)
val accountAbnormalities = AccountAbnormalities(testContext, crashReporter, this.coroutineContext) val accountAbnormalities = AccountAbnormalities(testContext, crashReporter, this.coroutineContext)
accountAbnormalities.accountManagerInitializedAsync( accountAbnormalities.accountManagerInitializedAsync(
@ -117,8 +116,9 @@ class AccountAbnormalitiesTest {
CompletableDeferred(Unit).also { it.complete(Unit) } CompletableDeferred(Unit).also { it.complete(Unit) }
).await() ).await()
accountAbnormalities.onAuthenticated(mock(), mock()) accountAbnormalities.onAuthenticated(mockk(), mockk())
verifyZeroInteractions(crashReporter) verify { crashReporter wasNot Called }
every { accountManager.authenticatedAccount() } returns null
// Pretend we restart, and instantiate a new middleware instance. // Pretend we restart, and instantiate a new middleware instance.
val accountAbnormalities2 = AccountAbnormalities(testContext, crashReporter, this.coroutineContext) val accountAbnormalities2 = AccountAbnormalities(testContext, crashReporter, this.coroutineContext)
@ -129,13 +129,13 @@ class AccountAbnormalitiesTest {
CompletableDeferred(Unit).also { it.complete(Unit) } CompletableDeferred(Unit).also { it.complete(Unit) }
).await() ).await()
assertCaughtException(crashReporter, AbnormalFxaEvent.MissingExpectedAccountAfterStartup::class) assertCaughtException<AbnormalFxaEvent.MissingExpectedAccountAfterStartup>(crashReporter)
} }
@Test @Test
fun `logout happy case`() = runBlocking { fun `logout happy case`() = runBlocking {
val crashReporter: CrashReporter = mock() val crashReporter: CrashReporter = mockk()
val accountManager: FxaAccountManager = mock() val accountManager: FxaAccountManager = mockk(relaxed = true)
val accountAbnormalities = AccountAbnormalities(testContext, crashReporter, this.coroutineContext) val accountAbnormalities = AccountAbnormalities(testContext, crashReporter, this.coroutineContext)
accountAbnormalities.accountManagerInitializedAsync( accountAbnormalities.accountManagerInitializedAsync(
@ -144,14 +144,14 @@ class AccountAbnormalitiesTest {
).await() ).await()
// We saw an auth event, then user requested a logout. // We saw an auth event, then user requested a logout.
accountAbnormalities.onAuthenticated(mock(), mock()) accountAbnormalities.onAuthenticated(mockk(), mockk())
accountAbnormalities.userRequestedLogout() accountAbnormalities.userRequestedLogout()
verifyZeroInteractions(crashReporter) verify { crashReporter wasNot Called }
} }
private fun <T : AbnormalFxaEvent> assertCaughtException(crashReporter: CrashReporter, type: KClass<T>) { private inline fun <reified T : AbnormalFxaEvent> assertCaughtException(crashReporter: CrashReporter) {
val captor = argumentCaptor<AbnormalFxaEvent>() verify {
verify(crashReporter).submitCaughtException(captor.capture()) crashReporter.submitCaughtException(any<T>())
assertEquals(type, captor.value::class) }
} }
} }

View File

@ -2,76 +2,74 @@ package org.mozilla.fenix.components
import android.view.View import android.view.View
import android.view.ViewStub 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.UserInteractionHandler
import mozilla.components.support.base.feature.LifecycleAwareFeature 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.junit.Test
import org.mockito.Mockito.never
import org.mockito.Mockito.spy
import org.mockito.Mockito.verify
import java.lang.ref.WeakReference import java.lang.ref.WeakReference
class InflationAwareFeatureTest { class InflationAwareFeatureTest {
@Test @Test
fun `stub inflates if no feature or view exists`() { fun `stub inflates if no feature or view exists`() {
val stub: ViewStub = mock() val stub: ViewStub = mockk(relaxed = true)
val feature: InflationAwareFeature = spy(TestableInflationAwareFeature(stub)) val feature: InflationAwareFeature = spyk(TestableInflationAwareFeature(stub))
feature.launch() feature.launch()
verify(stub).setOnInflateListener(any()) verify { stub.setOnInflateListener(any()) }
verify(stub).inflate() verify { stub.inflate() }
} }
@Test @Test
fun `stub immediately launches if the feature is available`() { fun `stub immediately launches if the feature is available`() {
val stub: ViewStub = mock() val stub: ViewStub = mockk()
val feature: InflationAwareFeature = spy(TestableInflationAwareFeature(stub)) val feature: InflationAwareFeature = spyk(TestableInflationAwareFeature(stub))
feature.feature = mock() feature.feature = mockk(relaxed = true)
feature.view = WeakReference(mock()) feature.view = WeakReference(mockk())
feature.launch() feature.launch()
verify(stub, never()).setOnInflateListener(any()) verify(exactly = 0) { stub.setOnInflateListener(any()) }
verify(stub, never()).inflate() verify(exactly = 0) { stub.inflate() }
verify(feature).onLaunch(any(), any()) verify { feature.onLaunch(any(), any()) }
} }
@Test @Test
fun `feature calls stop if created`() { fun `feature calls stop if created`() {
val stub: ViewStub = mock() val stub: ViewStub = mockk()
val inflationFeature: InflationAwareFeature = spy(TestableInflationAwareFeature(stub)) val inflationFeature: InflationAwareFeature = spyk(TestableInflationAwareFeature(stub))
val innerFeature: LifecycleAwareFeature = mock() val innerFeature: LifecycleAwareFeature = mockk(relaxed = true)
inflationFeature.stop() inflationFeature.stop()
verify(innerFeature, never()).stop() verify(exactly = 0) { innerFeature.stop() }
inflationFeature.feature = innerFeature inflationFeature.feature = innerFeature
inflationFeature.stop() inflationFeature.stop()
verify(innerFeature).stop() verify { innerFeature.stop() }
} }
@Test @Test
fun `start should be delegated to the inner feature`() { fun `start should be delegated to the inner feature`() {
val inflationFeature: InflationAwareFeature = spy(TestableInflationAwareFeature(mock())) val inflationFeature: InflationAwareFeature = spyk(TestableInflationAwareFeature(mockk()))
val innerFeature: LifecycleAwareFeature = mock() val innerFeature: LifecycleAwareFeature = mockk(relaxed = true)
inflationFeature.feature = innerFeature inflationFeature.feature = innerFeature
inflationFeature.start() inflationFeature.start()
verify(innerFeature).start() verify { innerFeature.start() }
} }
@Test @Test
fun `if feature has implemented UserInteractionHandler invoke it`() { fun `if feature has implemented UserInteractionHandler invoke it`() {
val stub: ViewStub = mock() val stub: ViewStub = mockk()
val inflationFeature: InflationAwareFeature = spy(TestableInflationAwareFeature(stub)) val inflationFeature: InflationAwareFeature = spyk(TestableInflationAwareFeature(stub))
val innerFeature: LifecycleAwareFeature = mock() val innerFeature: LifecycleAwareFeature = mockk()
val userInteractionHandlerFeature = object : LifecycleAwareFeature, UserInteractionHandler { val userInteractionHandlerFeature = object : LifecycleAwareFeature, UserInteractionHandler {
override fun onBackPressed() = true override fun onBackPressed() = true
@ -93,10 +91,7 @@ class InflationAwareFeatureTest {
} }
class TestableInflationAwareFeature(stub: ViewStub) : InflationAwareFeature(stub) { class TestableInflationAwareFeature(stub: ViewStub) : InflationAwareFeature(stub) {
override fun onViewInflated(view: View): LifecycleAwareFeature { override fun onViewInflated(view: View): LifecycleAwareFeature = mockk()
return mock()
}
override fun onLaunch(view: View, feature: LifecycleAwareFeature) { override fun onLaunch(view: View, feature: LifecycleAwareFeature) = Unit
}
} }

View File

@ -6,8 +6,6 @@ package org.mozilla.fenix.components
import android.content.Context import android.content.Context
import io.mockk.mockk import io.mockk.mockk
import mozilla.components.support.test.mock
import org.mockito.Mockito.`when`
import org.mozilla.fenix.utils.ClipboardHandler import org.mozilla.fenix.utils.ClipboardHandler
class TestComponents(private val context: Context) : Components(context) { class TestComponents(private val context: Context) : Components(context) {
@ -28,17 +26,7 @@ class TestComponents(private val context: Context) : Components(context) {
core.thumbnailStorage core.thumbnailStorage
) )
} }
override val intentProcessors by lazy { override val intentProcessors by lazy { mockk<IntentProcessors>(relaxed = true) }
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 analytics by lazy { Analytics(context) } override val analytics by lazy { Analytics(context) }
override val clipboardHandler by lazy { ClipboardHandler(context) } override val clipboardHandler by lazy { ClipboardHandler(context) }

View File

@ -6,17 +6,17 @@ package org.mozilla.fenix.components.metrics
import androidx.navigation.NavController import androidx.navigation.NavController
import androidx.navigation.NavDestination 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.Crash
import mozilla.components.lib.crash.CrashReporter import mozilla.components.lib.crash.CrashReporter
import mozilla.components.lib.crash.service.CrashReporterService import mozilla.components.lib.crash.service.CrashReporterService
import mozilla.components.support.base.crash.Breadcrumb 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.junit.Test
import org.mockito.Mockito.spy
import org.mockito.Mockito.verify
internal class BreadcrumbRecorderTest { internal class BreadcrumbRecorderTest {
@Test @Test
fun `ensure crash reporter recordCrashBreadcrumb is called`() { fun `ensure crash reporter recordCrashBreadcrumb is called`() {
val service = object : CrashReporterService { val service = object : CrashReporterService {
@ -28,9 +28,9 @@ internal class BreadcrumbRecorderTest {
override fun report(crash: Crash.UncaughtExceptionCrash): String? = "" override fun report(crash: Crash.UncaughtExceptionCrash): String? = ""
} }
val reporter = spy( val reporter = spyk(
CrashReporter( CrashReporter(
context = mock(), context = mockk(),
services = listOf(service), services = listOf(service),
shouldPrompt = CrashReporter.Prompt.NEVER shouldPrompt = CrashReporter.Prompt.NEVER
) )
@ -40,13 +40,13 @@ internal class BreadcrumbRecorderTest {
return "test" return "test"
} }
val navController: NavController = mock() val navController: NavController = mockk()
val navDestination: NavDestination = mock() val navDestination: NavDestination = mockk()
val breadCrumbRecorder = val breadCrumbRecorder =
BreadcrumbsRecorder(reporter, navController, ::getBreadcrumbMessage) BreadcrumbsRecorder(reporter, navController, ::getBreadcrumbMessage)
breadCrumbRecorder.onDestinationChanged(navController, navDestination, null) breadCrumbRecorder.onDestinationChanged(navController, navDestination, null)
verify(reporter).recordCrashBreadcrumb(any()) verify { reporter.recordCrashBreadcrumb(any()) }
} }
} }

View File

@ -10,24 +10,24 @@ import io.mockk.mockk
import io.mockk.mockkObject import io.mockk.mockkObject
import io.mockk.mockkStatic import io.mockk.mockkStatic
import io.mockk.slot import io.mockk.slot
import io.mockk.unmockkStatic
import kotlinx.coroutines.runBlocking import kotlinx.coroutines.runBlocking
import org.junit.Assert
import org.junit.Assert.assertEquals import org.junit.Assert.assertEquals
import org.junit.Ignore import org.junit.Assert.assertNull
import org.junit.Test import org.junit.Test
import org.mockito.ArgumentMatchers
import java.io.IOException import java.io.IOException
class MetricsUtilsTest { class MetricsUtilsTest {
private val context: Context = mockk(relaxed = true) private val context: Context = mockk(relaxed = true)
@Ignore("This test has side-effects that cause it to fail other unrelated tests.")
@Test @Test
fun `getAdvertisingID() returns null if the API throws`() { fun `getAdvertisingID() returns null if the API throws`() {
mockkStatic("com.google.android.gms.ads.identifier.AdvertisingIdClient")
val exceptions = listOf( val exceptions = listOf(
GooglePlayServicesNotAvailableException(1), GooglePlayServicesNotAvailableException(1),
GooglePlayServicesRepairableException(0, ArgumentMatchers.anyString(), ArgumentMatchers.any()), GooglePlayServicesRepairableException(0, "", mockk()),
IllegalStateException(), IllegalStateException(),
IOException() IOException()
) )
@ -37,8 +37,10 @@ class MetricsUtilsTest {
AdvertisingIdClient.getAdvertisingIdInfo(any()) AdvertisingIdClient.getAdvertisingIdInfo(any())
} throws it } throws it
Assert.assertNull(MetricsUtils.getAdvertisingID(context)) assertNull(MetricsUtils.getAdvertisingID(context))
} }
unmockkStatic("com.google.android.gms.ads.identifier.AdvertisingIdClient")
} }
@Test @Test
@ -46,7 +48,7 @@ class MetricsUtilsTest {
mockkStatic(AdvertisingIdClient::class) mockkStatic(AdvertisingIdClient::class)
every { AdvertisingIdClient.getAdvertisingIdInfo(any()) } returns null every { AdvertisingIdClient.getAdvertisingIdInfo(any()) } returns null
Assert.assertNull(MetricsUtils.getAdvertisingID(context)) assertNull(MetricsUtils.getAdvertisingID(context))
} }
@Test @Test

View File

@ -1,7 +1,8 @@
package org.mozilla.fenix.components.searchengine package org.mozilla.fenix.components.searchengine
import android.content.Context import android.content.Context
import android.graphics.Bitmap import io.mockk.every
import io.mockk.mockk
import kotlinx.coroutines.CompletableDeferred import kotlinx.coroutines.CompletableDeferred
import kotlinx.coroutines.Deferred import kotlinx.coroutines.Deferred
import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.ExperimentalCoroutinesApi
@ -15,8 +16,6 @@ import org.junit.Assert.assertEquals
import org.junit.Before import org.junit.Before
import org.junit.Test import org.junit.Test
import org.junit.runner.RunWith import org.junit.runner.RunWith
import org.mockito.Mockito.`when`
import org.mockito.Mockito.mock
import org.mozilla.fenix.helpers.FenixRobolectricTestRunner import org.mozilla.fenix.helpers.FenixRobolectricTestRunner
@ExperimentalCoroutinesApi @ExperimentalCoroutinesApi
@ -115,11 +114,10 @@ class FakeFenixSearchEngineProvider(context: Context) : FenixSearchEngineProvide
id: String, id: String,
n: String = id n: String = id
): SearchEngine { ): SearchEngine {
// Uses Mockito because of a strange Mockk error. Feel free to rewrite val engine = mockk<SearchEngine>()
return mock(SearchEngine::class.java).apply { every { engine.identifier } returns id
`when`(identifier).thenReturn(id) every { engine.name } returns n
`when`(name).thenReturn(n) every { engine.icon } returns mockk()
`when`(icon).thenReturn(mock(Bitmap::class.java)) return engine
}
} }
} }

View File

@ -9,14 +9,13 @@ import android.os.Bundle
import androidx.navigation.NavDirections import androidx.navigation.NavDirections
import io.mockk.every import io.mockk.every
import io.mockk.mockk import io.mockk.mockk
import io.mockk.spyk
import io.mockk.verify
import mozilla.components.support.utils.toSafeIntent import mozilla.components.support.utils.toSafeIntent
import org.junit.Assert.assertEquals import org.junit.Assert.assertEquals
import org.junit.Assert.assertNotNull import org.junit.Assert.assertNotNull
import org.junit.Assert.assertNull import org.junit.Assert.assertNull
import org.junit.Test 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.BrowserDirection
import org.mozilla.fenix.components.metrics.Event import org.mozilla.fenix.components.metrics.Event
@ -40,7 +39,7 @@ class ExternalAppBrowserActivityTest {
@Test @Test
fun `getNavDirections finishes activity if session ID is null`() { fun `getNavDirections finishes activity if session ID is null`() {
val activity = spy(object : ExternalAppBrowserActivity() { val activity = spyk(object : ExternalAppBrowserActivity() {
public override fun getNavDirections( public override fun getNavDirections(
from: BrowserDirection, from: BrowserDirection,
customTabSessionId: String? customTabSessionId: String?
@ -59,10 +58,10 @@ class ExternalAppBrowserActivityTest {
var directions = activity.getNavDirections(BrowserDirection.FromGlobal, "id") var directions = activity.getNavDirections(BrowserDirection.FromGlobal, "id")
assertNotNull(directions) assertNotNull(directions)
verify(activity, never()).finish() verify(exactly = 0) { activity.finish() }
directions = activity.getNavDirections(BrowserDirection.FromGlobal, null) directions = activity.getNavDirections(BrowserDirection.FromGlobal, null)
assertNull(directions) assertNull(directions)
verify(activity).finish() verify { activity.finish() }
} }
} }

View File

@ -4,12 +4,12 @@
package org.mozilla.fenix.customtabs package org.mozilla.fenix.customtabs
import io.mockk.mockk
import mozilla.components.browser.state.state.BrowserState import mozilla.components.browser.state.state.BrowserState
import mozilla.components.browser.state.state.CustomTabConfig import mozilla.components.browser.state.state.CustomTabConfig
import mozilla.components.browser.state.state.ExternalAppType import mozilla.components.browser.state.state.ExternalAppType
import mozilla.components.browser.state.state.createCustomTab import mozilla.components.browser.state.state.createCustomTab
import mozilla.components.browser.state.store.BrowserStore import mozilla.components.browser.state.store.BrowserStore
import mozilla.components.support.test.mock
import mozilla.components.support.test.robolectric.testContext import mozilla.components.support.test.robolectric.testContext
import org.junit.Test import org.junit.Test
import org.junit.runner.RunWith import org.junit.runner.RunWith
@ -50,7 +50,7 @@ class PoweredByNotificationTest {
@Test @Test
fun `unregister receiver on pause`() { fun `unregister receiver on pause`() {
val feature = PoweredByNotification(testContext, mock(), "session-id") val feature = PoweredByNotification(testContext, mockk(), "session-id")
feature.onPause() feature.onPause()
} }
} }

View File

@ -7,16 +7,15 @@ package org.mozilla.fenix.downloads
import android.animation.ValueAnimator import android.animation.ValueAnimator
import android.view.View import android.view.View
import androidx.core.view.ViewCompat 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 mozilla.components.support.test.robolectric.testContext
import org.junit.Assert.assertFalse import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue import org.junit.Assert.assertTrue
import org.junit.Test import org.junit.Test
import org.junit.runner.RunWith 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 import org.mozilla.fenix.helpers.FenixRobolectricTestRunner
@RunWith(FenixRobolectricTestRunner::class) @RunWith(FenixRobolectricTestRunner::class)
@ -24,24 +23,24 @@ class DynamicDownloadDialogBehaviorTest {
@Test @Test
fun `Starting a nested scroll should cancel an ongoing snap animation`() { fun `Starting a nested scroll should cancel an ongoing snap animation`() {
val behavior = spy(DynamicDownloadDialogBehavior<View>(testContext, attrs = null)) val behavior = spyk(DynamicDownloadDialogBehavior<View>(testContext, attrs = null))
doReturn(true).`when`(behavior).shouldScroll every { behavior.shouldScroll } returns true
val animator: ValueAnimator = mock() val animator: ValueAnimator = mockk(relaxed = true)
behavior.snapAnimator = animator behavior.snapAnimator = animator
val acceptsNestedScroll = behavior.onStartNestedScroll( val acceptsNestedScroll = behavior.onStartNestedScroll(
coordinatorLayout = mock(), coordinatorLayout = mockk(),
child = mock(), child = mockk(),
directTargetChild = mock(), directTargetChild = mockk(),
target = mock(), target = mockk(),
axes = ViewCompat.SCROLL_AXIS_VERTICAL, axes = ViewCompat.SCROLL_AXIS_VERTICAL,
type = ViewCompat.TYPE_TOUCH type = ViewCompat.TYPE_TOUCH
) )
assertTrue(acceptsNestedScroll) assertTrue(acceptsNestedScroll)
verify(animator).cancel() verify { animator.cancel() }
} }
@Test @Test
@ -49,10 +48,10 @@ class DynamicDownloadDialogBehaviorTest {
val behavior = DynamicDownloadDialogBehavior<View>(testContext, attrs = null) val behavior = DynamicDownloadDialogBehavior<View>(testContext, attrs = null)
val acceptsNestedScroll = behavior.onStartNestedScroll( val acceptsNestedScroll = behavior.onStartNestedScroll(
coordinatorLayout = mock(), coordinatorLayout = mockk(),
child = mock(), child = mockk(),
directTargetChild = mock(), directTargetChild = mockk(),
target = mock(), target = mockk(),
axes = ViewCompat.SCROLL_AXIS_HORIZONTAL, axes = ViewCompat.SCROLL_AXIS_HORIZONTAL,
type = ViewCompat.TYPE_TOUCH type = ViewCompat.TYPE_TOUCH
) )
@ -62,117 +61,123 @@ class DynamicDownloadDialogBehaviorTest {
@Test @Test
fun `Behavior will snap the dialog up if it is more than 50% visible`() { fun `Behavior will snap the dialog up if it is more than 50% visible`() {
val behavior = spy(DynamicDownloadDialogBehavior<View>(testContext, attrs = null, val behavior = spyk(DynamicDownloadDialogBehavior<View>(testContext, attrs = null,
bottomToolbarHeight = 10f)) 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.snapAnimator = animator
behavior.expanded = false behavior.expanded = false
val child = mock<View>() val child = mockk<View> {
doReturn(100).`when`(child)?.height every { height } returns 100
doReturn(59f).`when`(child)?.translationY every { translationY } returns 59f
}
behavior.onStartNestedScroll( behavior.onStartNestedScroll(
coordinatorLayout = mock(), coordinatorLayout = mockk(),
child = child, child = child,
directTargetChild = mock(), directTargetChild = mockk(),
target = mock(), target = mockk(),
axes = ViewCompat.SCROLL_AXIS_VERTICAL, axes = ViewCompat.SCROLL_AXIS_VERTICAL,
type = ViewCompat.TYPE_TOUCH type = ViewCompat.TYPE_TOUCH
) )
assertTrue(behavior.shouldSnapAfterScroll) assertTrue(behavior.shouldSnapAfterScroll)
verify(animator, never()).start() verify(exactly = 0) { animator.start() }
behavior.onStopNestedScroll( behavior.onStopNestedScroll(
coordinatorLayout = mock(), coordinatorLayout = mockk(),
child = child, child = child,
target = mock(), target = mockk(),
type = 0 type = 0
) )
verify(behavior).animateSnap(child, DynamicDownloadDialogBehavior.SnapDirection.UP) verify { behavior.animateSnap(child, DynamicDownloadDialogBehavior.SnapDirection.UP) }
verify(animator).start() verify { animator.start() }
} }
@Test @Test
fun `Behavior will snap the dialog down if translationY is at least equal to half the toolbarHeight`() { fun `Behavior will snap the dialog down if translationY is at least equal to half the toolbarHeight`() {
val behavior = spy(DynamicDownloadDialogBehavior<View>(testContext, attrs = null, val behavior = spyk(DynamicDownloadDialogBehavior<View>(testContext, attrs = null,
bottomToolbarHeight = 10f)) 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.snapAnimator = animator
behavior.expanded = true behavior.expanded = true
val child = mock<View>() val child = mockk<View> {
doReturn(100).`when`(child).height every { height } returns 100
doReturn(5f).`when`(child).translationY every { translationY } returns 5f
}
behavior.onStartNestedScroll( behavior.onStartNestedScroll(
coordinatorLayout = mock(), coordinatorLayout = mockk(),
child = child, child = child,
directTargetChild = mock(), directTargetChild = mockk(),
target = mock(), target = mockk(),
axes = ViewCompat.SCROLL_AXIS_VERTICAL, axes = ViewCompat.SCROLL_AXIS_VERTICAL,
type = ViewCompat.TYPE_TOUCH type = ViewCompat.TYPE_TOUCH
) )
assertTrue(behavior.shouldSnapAfterScroll) assertTrue(behavior.shouldSnapAfterScroll)
verify(animator, never()).start() verify(exactly = 0) { animator.start() }
behavior.onStopNestedScroll( behavior.onStopNestedScroll(
coordinatorLayout = mock(), coordinatorLayout = mockk(),
child = child, child = child,
target = mock(), target = mockk(),
type = 0 type = 0
) )
verify(behavior).animateSnap(child, DynamicDownloadDialogBehavior.SnapDirection.DOWN) verify { behavior.animateSnap(child, DynamicDownloadDialogBehavior.SnapDirection.DOWN) }
verify(animator).start() verify { animator.start() }
} }
@Test @Test
fun `Behavior will apply translation to the dialog for nested scroll`() { fun `Behavior will apply translation to the dialog for nested scroll`() {
val behavior = spy(DynamicDownloadDialogBehavior<View>(testContext, attrs = null)) val behavior = spyk(DynamicDownloadDialogBehavior<View>(testContext, attrs = null))
doReturn(true).`when`(behavior).shouldScroll every { behavior.shouldScroll } returns true
val child = mock<View>() val child = mockk<View> {
doReturn(100).`when`(child).height every { height } returns 100
doReturn(0f).`when`(child).translationY every { translationY } returns 0f
every { translationY = any() } returns Unit
}
behavior.onNestedPreScroll( behavior.onNestedPreScroll(
coordinatorLayout = mock(), coordinatorLayout = mockk(),
child = child, child = child,
target = mock(), target = mockk(),
dx = 0, dx = 0,
dy = 25, dy = 25,
consumed = IntArray(0), consumed = IntArray(0),
type = 0 type = 0
) )
verify(child).translationY = 25f verify { child.translationY = 25f }
} }
@Test @Test
fun `Behavior will animateSnap UP when forceExpand is called`() { fun `Behavior will animateSnap UP when forceExpand is called`() {
val behavior = spy(DynamicDownloadDialogBehavior<View>(testContext, attrs = null)) val behavior = spyk(DynamicDownloadDialogBehavior<View>(testContext, attrs = null))
val dynamicDialogView: View = mock() val dynamicDialogView: View = mockk(relaxed = true)
doReturn(true).`when`(behavior).shouldScroll every { behavior.shouldScroll } returns true
behavior.forceExpand(dynamicDialogView) behavior.forceExpand(dynamicDialogView)
verify(behavior).animateSnap( verify {
behavior.animateSnap(
dynamicDialogView, dynamicDialogView,
DynamicDownloadDialogBehavior.SnapDirection.UP DynamicDownloadDialogBehavior.SnapDirection.UP
) )
} }
} }
}

View File

@ -4,12 +4,13 @@
package org.mozilla.fenix.ext package org.mozilla.fenix.ext
import io.mockk.mockk
import mozilla.components.browser.session.Session import mozilla.components.browser.session.Session
import mozilla.components.browser.state.state.BrowserState import mozilla.components.browser.state.state.BrowserState
import mozilla.components.browser.state.state.ReaderState import mozilla.components.browser.state.state.ReaderState
import mozilla.components.browser.state.state.createTab import mozilla.components.browser.state.state.createTab
import mozilla.components.browser.state.store.BrowserStore 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.Assert.assertEquals
import org.junit.Test import org.junit.Test
import org.junit.runner.RunWith import org.junit.runner.RunWith
@ -36,8 +37,9 @@ class SessionTest {
val tabs = listOf(tabWithoutReaderState, tabWithInactiveReaderState, tabWithActiveReaderState) val tabs = listOf(tabWithoutReaderState, tabWithInactiveReaderState, tabWithActiveReaderState)
val store = BrowserStore(BrowserState(tabs)) val store = BrowserStore(BrowserState(tabs))
assertEquals(sessionWithoutReaderState.url, sessionWithoutReaderState.toTab(store, mock()).url) val suffixList = mockk<PublicSuffixList>(relaxed = true)
assertEquals(sessionWithInactiveReaderState.url, sessionWithInactiveReaderState.toTab(store, mock()).url) assertEquals(sessionWithoutReaderState.url, sessionWithoutReaderState.toTab(store, suffixList).url)
assertEquals("https://blog.mozilla.org/123", sessionWithActiveReaderState.toTab(store, mock()).url) assertEquals(sessionWithInactiveReaderState.url, sessionWithInactiveReaderState.toTab(store, suffixList).url)
assertEquals("https://blog.mozilla.org/123", sessionWithActiveReaderState.toTab(store, suffixList).url)
} }
} }

View File

@ -5,14 +5,14 @@
package org.mozilla.fenix.ext package org.mozilla.fenix.ext
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import io.mockk.every
import io.mockk.mockk
import mozilla.components.feature.tab.collections.TabCollection import mozilla.components.feature.tab.collections.TabCollection
import mozilla.components.support.test.mock
import mozilla.components.support.test.robolectric.testContext import mozilla.components.support.test.robolectric.testContext
import org.junit.Assert.assertEquals import org.junit.Assert.assertEquals
import org.junit.Assert.assertNotEquals import org.junit.Assert.assertNotEquals
import org.junit.Test import org.junit.Test
import org.junit.runner.RunWith import org.junit.runner.RunWith
import org.mockito.Mockito.`when`
import org.mozilla.fenix.R import org.mozilla.fenix.R
import org.mozilla.fenix.helpers.FenixRobolectricTestRunner import org.mozilla.fenix.helpers.FenixRobolectricTestRunner
@ -33,8 +33,8 @@ class TabCollectionTest {
} }
private fun mockTabCollection(id: Long): TabCollection { private fun mockTabCollection(id: Long): TabCollection {
val collection: TabCollection = mock() val collection: TabCollection = mockk()
`when`(collection.id).thenReturn(id) every { collection.id } returns id
return collection return collection
} }
} }

View File

@ -10,14 +10,16 @@ import io.mockk.Called
import io.mockk.every import io.mockk.every
import io.mockk.mockk import io.mockk.mockk
import io.mockk.verify import io.mockk.verify
import mozilla.components.browser.search.SearchEngine
import org.junit.Before
import org.junit.Test import org.junit.Test
import org.junit.runner.RunWith import org.junit.runner.RunWith
import org.mozilla.fenix.BrowserDirection import org.mozilla.fenix.BrowserDirection
import org.mozilla.fenix.HomeActivity import org.mozilla.fenix.HomeActivity
import org.mozilla.fenix.components.metrics.MetricController import org.mozilla.fenix.components.metrics.MetricController
import org.mozilla.fenix.ext.components 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.helpers.FenixRobolectricTestRunner
import org.mozilla.fenix.widget.VoiceSearchActivity.Companion.SPEECH_PROCESSING
@RunWith(FenixRobolectricTestRunner::class) @RunWith(FenixRobolectricTestRunner::class)
class SpeechProcessingIntentProcessorTest { class SpeechProcessingIntentProcessorTest {
@ -27,6 +29,13 @@ class SpeechProcessingIntentProcessorTest {
private val out: Intent = mockk(relaxed = true) private val out: Intent = mockk(relaxed = true)
private val metrics: MetricController = mockk(relaxed = true) private val metrics: MetricController = mockk(relaxed = true)
@Before
fun setup() {
val searchEngine = mockk<SearchEngine>(relaxed = true)
every { activity.components.search.searchEngineManager.defaultSearchEngine } returns searchEngine
every { activity.components.search.provider.getDefaultEngine(activity) } returns searchEngine
}
@Test @Test
fun `do not process blank intents`() { fun `do not process blank intents`() {
val processor = SpeechProcessingIntentProcessor(activity, metrics) val processor = SpeechProcessingIntentProcessor(activity, metrics)
@ -58,7 +67,6 @@ class SpeechProcessingIntentProcessorTest {
putExtra(HomeActivity.OPEN_TO_BROWSER_AND_LOAD, true) putExtra(HomeActivity.OPEN_TO_BROWSER_AND_LOAD, true)
} }
val processor = SpeechProcessingIntentProcessor(activity, metrics) val processor = SpeechProcessingIntentProcessor(activity, metrics)
every { activity.components.search.provider.getDefaultEngine(activity) } returns mockk(relaxed = true)
processor.process(intent, navController, out) processor.process(intent, navController, out)
@ -81,7 +89,6 @@ class SpeechProcessingIntentProcessorTest {
putExtra(SPEECH_PROCESSING, "hello world") putExtra(SPEECH_PROCESSING, "hello world")
} }
val processor = SpeechProcessingIntentProcessor(activity, metrics) val processor = SpeechProcessingIntentProcessor(activity, metrics)
every { activity.components.search.provider.getDefaultEngine(activity) } returns mockk(relaxed = true)
processor.process(intent, mockk(), mockk(relaxed = true)) processor.process(intent, mockk(), mockk(relaxed = true))

View File

@ -20,6 +20,7 @@ import org.junit.Assert.assertTrue
import org.junit.Before import org.junit.Before
import org.junit.Test import org.junit.Test
import org.junit.runner.RunWith import org.junit.runner.RunWith
import org.mozilla.fenix.R
import org.mozilla.fenix.browser.browsingmode.BrowsingMode import org.mozilla.fenix.browser.browsingmode.BrowsingMode
import org.mozilla.fenix.components.FenixSnackbar import org.mozilla.fenix.components.FenixSnackbar
import org.mozilla.fenix.helpers.FenixRobolectricTestRunner import org.mozilla.fenix.helpers.FenixRobolectricTestRunner
@ -182,8 +183,8 @@ class HistoryControllerTest {
} }
assertEquals( assertEquals(
directions.captured::class.simpleName, directions.captured.actionId,
"ActionGlobalShareFragment" R.id.action_global_shareFragment
) )
assertEquals(1, (directions.captured.arguments["data"] as Array<ShareData>).size) assertEquals(1, (directions.captured.arguments["data"] as Array<ShareData>).size)
assertEquals(historyItem.title, (directions.captured.arguments["data"] as Array<ShareData>)[0].title) assertEquals(historyItem.title, (directions.captured.arguments["data"] as Array<ShareData>)[0].title)

View File

@ -14,7 +14,6 @@ import io.mockk.mockkObject
import io.mockk.mockkStatic import io.mockk.mockkStatic
import io.mockk.verify import io.mockk.verify
import mozilla.components.support.locale.LocaleManager import mozilla.components.support.locale.LocaleManager
import mozilla.components.support.test.mock
import org.junit.Before import org.junit.Before
import org.junit.Test import org.junit.Test
import java.util.Locale import java.util.Locale
@ -61,7 +60,7 @@ class LocaleSettingsControllerTest {
@Test @Test
fun `set a new locale from the list`() { fun `set a new locale from the list`() {
val selectedLocale = Locale("en", "UK") val selectedLocale = Locale("en", "UK")
val otherLocale: Locale = mock() val otherLocale: Locale = mockk()
every { localeSettingsStore.state } returns LocaleSettingsState( every { localeSettingsStore.state } returns LocaleSettingsState(
mockk(), mockk(),
mockk(), mockk(),

View File

@ -11,6 +11,7 @@ import android.content.pm.ResolveInfo
import android.graphics.drawable.Drawable import android.graphics.drawable.Drawable
import android.net.ConnectivityManager import android.net.ConnectivityManager
import androidx.core.content.getSystemService import androidx.core.content.getSystemService
import androidx.lifecycle.asFlow
import io.mockk.Runs import io.mockk.Runs
import io.mockk.every import io.mockk.every
import io.mockk.just import io.mockk.just
@ -18,8 +19,8 @@ import io.mockk.mockk
import io.mockk.mockkStatic import io.mockk.mockkStatic
import io.mockk.spyk import io.mockk.spyk
import io.mockk.verify import io.mockk.verify
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.test.TestCoroutineDispatcher import kotlinx.coroutines.test.TestCoroutineDispatcher
import kotlinx.coroutines.test.runBlockingTest import kotlinx.coroutines.test.runBlockingTest
import mozilla.components.feature.share.RecentApp 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.application
import org.mozilla.fenix.ext.components import org.mozilla.fenix.ext.components
import org.mozilla.fenix.ext.isOnline 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.ShareViewModel.Companion.RECENT_APPS_LIMIT
import org.mozilla.fenix.share.listadapters.AppShareOption import org.mozilla.fenix.share.listadapters.AppShareOption
import org.mozilla.fenix.share.listadapters.SyncShareOption import org.mozilla.fenix.share.listadapters.SyncShareOption
import org.mozilla.fenix.helpers.FenixRobolectricTestRunner
@RunWith(FenixRobolectricTestRunner::class) @RunWith(FenixRobolectricTestRunner::class)
@ExperimentalCoroutinesApi @ExperimentalCoroutinesApi
class ShareViewModelTest { class ShareViewModelTest {
private val packageName = "org.mozilla.fenix" private val packageName = "org.mozilla.fenix"
private val testIoDispatcher = TestCoroutineDispatcher()
private lateinit var application: Application private lateinit var application: Application
private lateinit var packageManager: PackageManager private lateinit var packageManager: PackageManager
private lateinit var connectivityManager: ConnectivityManager private lateinit var connectivityManager: ConnectivityManager
private lateinit var fxaAccountManager: FxaAccountManager private lateinit var fxaAccountManager: FxaAccountManager
private lateinit var viewModel: ShareViewModel private lateinit var viewModel: ShareViewModel
private lateinit var storage: RecentAppsStorage
@Before @Before
fun setup() { fun setup() {
@ -55,6 +58,7 @@ class ShareViewModelTest {
packageManager = mockk(relaxed = true) packageManager = mockk(relaxed = true)
connectivityManager = mockk(relaxed = true) connectivityManager = mockk(relaxed = true)
fxaAccountManager = mockk(relaxed = true) fxaAccountManager = mockk(relaxed = true)
storage = mockk(relaxUnitFun = true)
mockkStatic("org.mozilla.fenix.ext.ConnectivityManagerKt") mockkStatic("org.mozilla.fenix.ext.ConnectivityManagerKt")
@ -63,7 +67,8 @@ class ShareViewModelTest {
every { application.getSystemService<ConnectivityManager>() } returns connectivityManager every { application.getSystemService<ConnectivityManager>() } returns connectivityManager
every { application.components.backgroundServices.accountManager } returns fxaAccountManager every { application.components.backgroundServices.accountManager } returns fxaAccountManager
viewModel = ShareViewModel(application) viewModel = spyk(ShareViewModel(application))
viewModel.ioDispatcher = testIoDispatcher
} }
@Test @Test
@ -73,28 +78,20 @@ class ShareViewModelTest {
} }
@Test @Test
fun `loadDevicesAndApps`() = runBlockingTest { fun `test loadDevicesAndApps`() = runBlockingTest {
mockkStatic(Dispatchers::class) val appOptions = listOf(
every { AppShareOption("Label", mockk(), "Package", "Activity")
Dispatchers.IO )
} returns TestCoroutineDispatcher()
viewModel = spyk(viewModel)
val drawable: Drawable = mockk()
val appOptions = ArrayList<AppShareOption>()
val appElement = AppShareOption("Label", drawable, "Package", "Activity")
appOptions.add(appElement)
val recentAppOptions = ArrayList<RecentApp>() val appEntity = mockk<RecentApp>()
val appEntity: RecentApp = mockk()
every { appEntity.activityName } returns "Activity" every { appEntity.activityName } returns "Activity"
recentAppOptions.add(appEntity) val recentAppOptions = listOf(appEntity)
val storage: RecentAppsStorage = mockk(relaxed = true)
viewModel.recentAppsStorage = storage
every { viewModel.buildAppsList(any(), any()) } returns appOptions
every { storage.updateDatabaseWithNewApps(appOptions.map { app -> app.packageName }) } just Runs every { storage.updateDatabaseWithNewApps(appOptions.map { app -> app.packageName }) } just Runs
every { storage.getRecentAppsUpTo(RECENT_APPS_LIMIT) } returns recentAppOptions every { storage.getRecentAppsUpTo(RECENT_APPS_LIMIT) } returns recentAppOptions
every { viewModel.buildAppsList(any(), any()) } returns appOptions
viewModel.recentAppsStorage = storage
viewModel.loadDevicesAndApps() viewModel.loadDevicesAndApps()
verify { verify {
@ -103,8 +100,8 @@ class ShareViewModelTest {
any<ConnectivityManager.NetworkCallback>() any<ConnectivityManager.NetworkCallback>()
) )
} }
assertEquals(1, viewModel.recentAppsList.value?.size) assertEquals(1, viewModel.recentAppsList.asFlow().first().size)
assertEquals(0, viewModel.appsList.value?.size) assertEquals(0, viewModel.appsList.asFlow().first().size)
} }
@Test @Test

View File

@ -6,14 +6,16 @@ package org.mozilla.fenix.tabtray
import android.view.LayoutInflater import android.view.LayoutInflater
import androidx.test.core.app.ApplicationProvider 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.mockk
import io.mockk.spyk
import mozilla.components.browser.toolbar.MAX_URI_LENGTH import mozilla.components.browser.toolbar.MAX_URI_LENGTH
import mozilla.components.concept.tabstray.Tab import mozilla.components.concept.tabstray.Tab
import org.junit.Assert.assertEquals import org.junit.Assert.assertEquals
import org.junit.Test import org.junit.Test
import org.junit.runner.RunWith import org.junit.runner.RunWith
import org.mockito.Mockito.doNothing
import org.mockito.Mockito.spy
import org.mozilla.fenix.R import org.mozilla.fenix.R
import org.mozilla.fenix.helpers.FenixRobolectricTestRunner import org.mozilla.fenix.helpers.FenixRobolectricTestRunner
@ -25,8 +27,8 @@ class TabTrayViewHolderTest {
val view = LayoutInflater.from(ApplicationProvider.getApplicationContext()).inflate( val view = LayoutInflater.from(ApplicationProvider.getApplicationContext()).inflate(
R.layout.tab_tray_item, null, false) R.layout.tab_tray_item, null, false)
val tabViewHolder = spy(TabTrayViewHolder(view) { null }) val tabViewHolder = spyk(TabTrayViewHolder(view) { null })
doNothing().`when`(tabViewHolder).updateBackgroundColor(false) every { tabViewHolder.updateBackgroundColor(false) } just Runs
val extremelyLongUrl = "m".repeat(MAX_URI_LENGTH + 1) val extremelyLongUrl = "m".repeat(MAX_URI_LENGTH + 1)
val tab = Tab( val tab = Tab(

View File

@ -37,7 +37,6 @@ object Versions {
const val installreferrer = "1.0" const val installreferrer = "1.0"
const val junit = "5.5.2" const val junit = "5.5.2"
const val mockito = "2.24.5"
const val mockk = "1.10.0" const val mockk = "1.10.0"
const val mockwebserver = "3.11.0" const val mockwebserver = "3.11.0"
@ -176,8 +175,6 @@ object Deps {
const val installreferrer = "com.android.installreferrer:installreferrer:${Versions.installreferrer}" const val installreferrer = "com.android.installreferrer:installreferrer:${Versions.installreferrer}"
const val junit = "junit:junit:${Versions.junit}" 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}" const val mockk = "io.mockk:mockk:${Versions.mockk}"
// --- START AndroidX test dependencies --- // // --- START AndroidX test dependencies --- //