Skip to content
This repository has been archived by the owner on Feb 20, 2023. It is now read-only.

Commit

Permalink
For #1710: Create scaffolding for Robolectric tests
Browse files Browse the repository at this point in the history
  • Loading branch information
colintheshots committed May 7, 2019
1 parent b735cc9 commit 4dd43c3
Show file tree
Hide file tree
Showing 28 changed files with 239 additions and 49 deletions.
11 changes: 7 additions & 4 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ android {

testOptions {
execution 'ANDROIDX_TEST_ORCHESTRATOR'
unitTests.includeAndroidResources = true
}

flavorDimensions "abi"
Expand Down Expand Up @@ -122,7 +123,7 @@ android.applicationVariants.all { variant ->
if (hasTest) {
apply plugin: 'kotlin-allopen'
allOpen {
annotation("org.mozilla.fenix.test.Mockable")
annotation("org.mozilla.fenix.test.OpenClass")
}
}

Expand Down Expand Up @@ -373,9 +374,11 @@ dependencies {
exclude group: 'com.android.support', module: 'support-annotations'
}

testImplementation Deps.junit_jupiter_api
testImplementation Deps.junit_jupiter_params
testImplementation Deps.junit_jupiter_engine
testImplementation Deps.junit
testImplementation Deps.robolectric
debugImplementation Deps.fragment_testing
testImplementation Deps.megazord_forUnitTests
testImplementation Deps.places_forUnitTests

testImplementation Deps.mockito_core
androidTestImplementation Deps.mockito_android
Expand Down
6 changes: 5 additions & 1 deletion app/src/main/java/org/mozilla/fenix/FenixApplication.kt
Original file line number Diff line number Diff line change
Expand Up @@ -28,16 +28,20 @@ import org.mozilla.fenix.utils.Settings
import java.io.File

@SuppressLint("Registered")
@Suppress("TooManyFunctions")
open class FenixApplication : Application() {
lateinit var fretboard: Fretboard
lateinit var experimentLoader: Deferred<Boolean>
var experimentLoaderComplete: Boolean = false

val components by lazy { Components(this) }
open val components by lazy { Components(this) }

override fun onCreate() {
super.onCreate()
setupApplication()
}

open fun setupApplication() {
// loadExperiments does things that run in parallel with the rest of setup.
// Call the function as early as possible so there's maximum overlap.
experimentLoader = loadExperiments()
Expand Down
2 changes: 2 additions & 0 deletions app/src/main/java/org/mozilla/fenix/components/Analytics.kt
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,15 @@ import org.mozilla.fenix.components.metrics.AdjustMetricsService
import org.mozilla.fenix.components.metrics.GleanMetricsService
import org.mozilla.fenix.components.metrics.LeanplumMetricsService
import org.mozilla.fenix.components.metrics.MetricController
import org.mozilla.fenix.test.Mockable
import org.mozilla.fenix.utils.Settings
import org.mozilla.geckoview.BuildConfig.MOZ_APP_BUILDID
import org.mozilla.geckoview.BuildConfig.MOZ_APP_VERSION

/**
* Component group for all functionality related to analytics e.g. crash reporting and telemetry.
*/
@Mockable
class Analytics(
private val context: Context
) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,13 @@ import mozilla.components.feature.sync.BackgroundSyncManager
import mozilla.components.feature.sync.GlobalSyncableStoreProvider
import mozilla.components.service.fxa.Config
import mozilla.components.service.fxa.FxaAccountManager
import org.mozilla.fenix.test.Mockable

/**
* Component group for background services. These are the components that need to be accessed from within a
* background worker.
*/
@Mockable
class BackgroundServices(
context: Context,
historyStorage: PlacesHistoryStorage,
Expand Down
2 changes: 2 additions & 0 deletions app/src/main/java/org/mozilla/fenix/components/Components.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,12 @@
package org.mozilla.fenix.components

import android.content.Context
import org.mozilla.fenix.test.Mockable

/**
* Provides access to all components.
*/
@Mockable
class Components(private val context: Context) {
val backgroundServices by lazy { BackgroundServices(context, core.historyStorage, core.bookmarksStorage) }
val services by lazy { Services(backgroundServices.accountManager, useCases.tabsUseCases) }
Expand Down
4 changes: 3 additions & 1 deletion app/src/main/java/org/mozilla/fenix/components/Core.kt
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import mozilla.components.concept.fetch.Client
import mozilla.components.feature.session.HistoryDelegate
import mozilla.components.lib.crash.handler.CrashHandlerService
import org.mozilla.fenix.AppRequestInterceptor
import org.mozilla.fenix.test.Mockable
import org.mozilla.fenix.utils.Settings
import org.mozilla.geckoview.GeckoRuntime
import org.mozilla.geckoview.GeckoRuntimeSettings
Expand All @@ -33,9 +34,10 @@ import java.util.concurrent.TimeUnit
/**
* Component group for all core browser functionality.
*/
@Mockable
class Core(private val context: Context) {

private val runtime by lazy {
protected val runtime by lazy {
val builder = GeckoRuntimeSettings.Builder()

testConfig?.let {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,20 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/. */
package org.mozilla.fenix.components

import android.util.TypedValue
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import com.google.android.material.snackbar.BaseTransientBottomBar
import android.view.LayoutInflater
import android.widget.FrameLayout
import androidx.coordinatorlayout.widget.CoordinatorLayout
import androidx.core.widget.TextViewCompat
import com.google.android.material.snackbar.BaseTransientBottomBar
import com.google.android.material.snackbar.Snackbar
import kotlinx.android.synthetic.main.fenix_snackbar.view.*
import org.mozilla.fenix.R
import org.mozilla.fenix.ext.increaseTapArea
import org.mozilla.fenix.test.Mockable

@Mockable
class FenixSnackbar private constructor(
parent: ViewGroup,
content: View,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@ import mozilla.components.feature.findinpage.view.FindInPageBar
import mozilla.components.feature.findinpage.view.FindInPageView
import mozilla.components.support.base.feature.BackHandler
import mozilla.components.support.base.feature.LifecycleAwareFeature
import org.mozilla.fenix.test.Mockable

@Mockable
class FindInPageIntegration(
private val sessionManager: SessionManager,
private val view: FindInPageView,
Expand Down
2 changes: 2 additions & 0 deletions app/src/main/java/org/mozilla/fenix/components/Search.kt
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,13 @@ import android.content.Context
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import mozilla.components.browser.search.SearchEngineManager
import org.mozilla.fenix.test.Mockable
import org.mozilla.fenix.utils.Settings

/**
* Component group for all search engine integration related functionality.
*/
@Mockable
class Search(private val context: Context) {

/**
Expand Down
2 changes: 2 additions & 0 deletions app/src/main/java/org/mozilla/fenix/components/Services.kt
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,12 @@ package org.mozilla.fenix.components
import mozilla.components.feature.accounts.FirefoxAccountsAuthFeature
import mozilla.components.feature.tabs.TabsUseCases
import mozilla.components.service.fxa.FxaAccountManager
import org.mozilla.fenix.test.Mockable

/**
* Component group which encapsulates foreground-friendly services.
*/
@Mockable
class Services(
private val accountManager: FxaAccountManager,
private val tabsUseCases: TabsUseCases
Expand Down
2 changes: 2 additions & 0 deletions app/src/main/java/org/mozilla/fenix/components/Storage.kt
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@ import androidx.paging.DataSource
import mozilla.components.feature.sitepermissions.SitePermissions
import mozilla.components.feature.sitepermissions.SitePermissions.Status
import mozilla.components.feature.sitepermissions.SitePermissionsStorage
import org.mozilla.fenix.test.Mockable

@Mockable
class Storage(private val context: Context) {

private val permissionsStorage by lazy {
Expand Down
2 changes: 2 additions & 0 deletions app/src/main/java/org/mozilla/fenix/components/UseCases.kt
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,13 @@ import mozilla.components.browser.session.SessionManager
import mozilla.components.feature.search.SearchUseCases
import mozilla.components.feature.session.SessionUseCases
import mozilla.components.feature.tabs.TabsUseCases
import org.mozilla.fenix.test.Mockable

/**
* Component group for all use cases. Use cases are provided by feature
* modules and can be triggered by UI interactions.
*/
@Mockable
class UseCases(
private val context: Context,
private val sessionManager: SessionManager,
Expand Down
2 changes: 2 additions & 0 deletions app/src/main/java/org/mozilla/fenix/components/Utilities.kt
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,12 @@ import mozilla.components.feature.intent.IntentProcessor
import mozilla.components.feature.search.SearchUseCases
import mozilla.components.feature.session.SessionUseCases
import org.mozilla.fenix.ext.components
import org.mozilla.fenix.test.Mockable

/**
* Component group for miscellaneous components.
*/
@Mockable
class Utilities(
private val context: Context,
private val sessionManager: SessionManager,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,15 +58,16 @@ class BookmarkFragment : Fragment(), CoroutineScope, BackHandler, AccountObserve
private lateinit var job: Job
private lateinit var bookmarkComponent: BookmarkComponent
private lateinit var signInComponent: SignInComponent
private var currentRoot: BookmarkNode? = null
private val navigation by lazy { Navigation.findNavController(requireActivity(), R.id.container) }
var currentRoot: BookmarkNode? = null
private val navigation by lazy { Navigation.findNavController(requireView()) }
private val onDestinationChangedListener =
NavController.OnDestinationChangedListener { _, destination, args ->
if (destination.id != R.id.bookmarkFragment ||
args != null && BookmarkFragmentArgs.fromBundle(args).currentRoot != currentRoot?.guid
)
getManagedEmitter<BookmarkChange>().onNext(BookmarkChange.ClearSelection)
}
lateinit var initialJob: Job

override val coroutineContext: CoroutineContext
get() = Main + job
Expand All @@ -81,19 +82,23 @@ class BookmarkFragment : Fragment(), CoroutineScope, BackHandler, AccountObserve
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
job = Job()
(activity as AppCompatActivity).title = getString(R.string.library_bookmarks)
activity?.title = getString(R.string.library_bookmarks)
setHasOptionsMenu(true)
}

override fun onResume() {
super.onResume()
(activity as AppCompatActivity).supportActionBar?.show()
(activity as? AppCompatActivity)?.supportActionBar?.show()
checkIfSignedIn()

navigation.addOnDestinationChangedListener(onDestinationChangedListener)
val currentGuid = BookmarkFragmentArgs.fromBundle(arguments!!).currentRoot.ifEmpty { BookmarkRoot.Mobile.id }

launch(IO) {
initialJob = loadInitialBookmarkFolder(currentGuid)
}

private fun loadInitialBookmarkFolder(currentGuid: String): Job {
return launch(IO) {
currentRoot = requireComponents.core.bookmarksStorage.getTree(currentGuid) as BookmarkNode

launch(Main) {
Expand Down Expand Up @@ -322,7 +327,8 @@ class BookmarkFragment : Fragment(), CoroutineScope, BackHandler, AccountObserve
override fun onProfileUpdated(profile: Profile) {
}

private fun getSelectedBookmarks() = (bookmarkComponent.uiView as BookmarkUIView).getSelected()
fun getBookmarks() = (bookmarkComponent.uiView as BookmarkUIView).tree?.children
fun getSelectedBookmarks() = (bookmarkComponent.uiView as BookmarkUIView).getSelected()

private suspend fun deleteSelectedBookmarks(
selected: Set<BookmarkNode> = getSelectedBookmarks(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,23 +92,24 @@ class BookmarkUIView(
fun getSelected(): Set<BookmarkNode> = bookmarkAdapter.selected

private fun setToolbarColors(foreground: Int, background: Int) {
val toolbar = (activity as AppCompatActivity).findViewById<Toolbar>(R.id.navigationToolbar)
val toolbar = activity?.findViewById<Toolbar>(R.id.navigationToolbar)
val colorFilter = PorterDuffColorFilter(
ContextCompat.getColor(context, foreground), PorterDuff.Mode.SRC_IN
)
toolbar.setBackgroundColor(ContextCompat.getColor(context, background))
toolbar.setTitleTextColor(ContextCompat.getColor(context, foreground))

themeToolbar(
toolbar, foreground,
background, colorFilter
)
toolbar?.run {
setBackgroundColor(ContextCompat.getColor(context, background))
setTitleTextColor(ContextCompat.getColor(context, foreground))
themeToolbar(
toolbar, foreground,
background, colorFilter
)
}
}

private fun setUIForSelectingMode(
mode: BookmarkState.Mode.Selecting
) {
(activity as? AppCompatActivity)?.title =
activity?.title =
context.getString(R.string.bookmarks_multi_select_title, mode.selectedItems.size)
setToolbarColors(
R.color.white_color,
Expand Down
17 changes: 17 additions & 0 deletions app/src/test/java/org/mozilla/fenix/TestApplication.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
License, v. 2.0. If a copy of the MPL was not distributed with this
file, You can obtain one at http://mozilla.org/MPL/2.0/. */

package org.mozilla.fenix

import org.mozilla.fenix.components.Components
import org.mozilla.fenix.components.TestComponents

class TestApplication : FenixApplication() {

override val components: Components
get() = TestComponents(this)

override fun setupApplication() {
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
License, v. 2.0. If a copy of the MPL was not distributed with this
file, You can obtain one at http://mozilla.org/MPL/2.0/. */

package org.mozilla.fenix.components

import android.content.Context
import mozilla.components.browser.storage.sync.PlacesBookmarksStorage
import mozilla.components.browser.storage.sync.PlacesHistoryStorage
import mozilla.components.feature.sync.BackgroundSyncManager

class TestBackgroundServices(
context: Context,
historyStorage: PlacesHistoryStorage,
bookmarksStorage: PlacesBookmarksStorage
) : BackgroundServices(context, historyStorage, bookmarksStorage) {
override val syncManager = BackgroundSyncManager("")
}
24 changes: 24 additions & 0 deletions app/src/test/java/org/mozilla/fenix/components/TestComponents.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package org.mozilla.fenix.components

import android.content.Context
import io.mockk.mockk

class TestComponents(private val context: Context) : Components(context) {
override val backgroundServices by lazy {
mockk<BackgroundServices>(relaxed = true)
}
override val services by lazy { Services(backgroundServices.accountManager, useCases.tabsUseCases) }
override val core by lazy { TestCore(context) }
override val search by lazy { Search(context) }
override val useCases by lazy { UseCases(context, core.sessionManager, search.searchEngineManager) }
override val utils by lazy {
Utilities(
context,
core.sessionManager,
useCases.sessionUseCases,
useCases.searchUseCases
)
}
override val analytics by lazy { Analytics(context) }
override val storage by lazy { Storage(context) }
}
20 changes: 20 additions & 0 deletions app/src/test/java/org/mozilla/fenix/components/TestCore.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
License, v. 2.0. If a copy of the MPL was not distributed with this
file, You can obtain one at http://mozilla.org/MPL/2.0/. */

package org.mozilla.fenix.components

import android.content.Context
import io.mockk.mockk
import kotlinx.coroutines.ObsoleteCoroutinesApi
import mozilla.components.browser.engine.gecko.GeckoEngine
import mozilla.components.browser.session.SessionManager
import org.mozilla.geckoview.GeckoRuntime

@ObsoleteCoroutinesApi
class TestCore(private val context: Context) : Core(context) {

override val runtime = mockk<GeckoRuntime>(relaxed = true)
override val engine = mockk<GeckoEngine>(relaxed = true)
override val sessionManager = SessionManager(engine)
}
Loading

0 comments on commit 4dd43c3

Please sign in to comment.