From 96b68948b5a868baecb2df2cf40b479a7c1c2860 Mon Sep 17 00:00:00 2001 From: Colin Lee Date: Tue, 7 May 2019 16:36:37 -0500 Subject: [PATCH] For #1710: Create scaffolding for Robolectric tests (#2282) --- app/build.gradle | 11 ++-- .../org/mozilla/fenix/FenixApplication.kt | 6 +- .../org/mozilla/fenix/components/Analytics.kt | 2 + .../fenix/components/BackgroundServices.kt | 2 + .../mozilla/fenix/components/Components.kt | 2 + .../java/org/mozilla/fenix/components/Core.kt | 4 +- .../mozilla/fenix/components/FenixSnackbar.kt | 6 +- .../fenix/components/FindInPageIntegration.kt | 2 + .../org/mozilla/fenix/components/Search.kt | 2 + .../org/mozilla/fenix/components/Services.kt | 2 + .../org/mozilla/fenix/components/Storage.kt | 2 + .../org/mozilla/fenix/components/UseCases.kt | 2 + .../org/mozilla/fenix/components/Utilities.kt | 2 + .../library/bookmarks/BookmarkFragment.kt | 18 ++++-- .../fenix/library/bookmarks/BookmarkUIView.kt | 19 +++--- .../java/org/mozilla/fenix/TestApplication.kt | 17 ++++++ .../components/TestBackgroundServices.kt | 18 ++++++ .../fenix/components/TestComponents.kt | 24 ++++++++ .../org/mozilla/fenix/components/TestCore.kt | 20 +++++++ .../components/metrics/ActivationPingTest.kt | 6 +- .../library/bookmarks/BookmarkAdapterTest.kt | 6 +- .../bookmarks/BookmarkComponentTest.kt | 6 +- .../library/bookmarks/BookmarkFragmentTest.kt | 60 +++++++++++++++++++ .../library/history/HistoryComponentTest.kt | 6 +- .../java/org/mozilla/fenix/test/Mockable.kt | 7 --- .../java/org/mozilla/fenix/test/OpenClass.kt | 18 ++++++ buildSrc/src/main/java/Dependencies.kt | 15 +++-- gradle.properties | 3 +- 28 files changed, 239 insertions(+), 49 deletions(-) create mode 100644 app/src/test/java/org/mozilla/fenix/TestApplication.kt create mode 100644 app/src/test/java/org/mozilla/fenix/components/TestBackgroundServices.kt create mode 100644 app/src/test/java/org/mozilla/fenix/components/TestComponents.kt create mode 100644 app/src/test/java/org/mozilla/fenix/components/TestCore.kt create mode 100644 app/src/test/java/org/mozilla/fenix/library/bookmarks/BookmarkFragmentTest.kt delete mode 100644 architecture/src/main/java/org/mozilla/fenix/test/Mockable.kt create mode 100644 architecture/src/main/java/org/mozilla/fenix/test/OpenClass.kt diff --git a/app/build.gradle b/app/build.gradle index 5fe6a6ff4..fd8c647e8 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -73,6 +73,7 @@ android { testOptions { execution 'ANDROIDX_TEST_ORCHESTRATOR' + unitTests.includeAndroidResources = true } flavorDimensions "abi" @@ -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") } } @@ -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 diff --git a/app/src/main/java/org/mozilla/fenix/FenixApplication.kt b/app/src/main/java/org/mozilla/fenix/FenixApplication.kt index 3150a8494..7f85be90a 100644 --- a/app/src/main/java/org/mozilla/fenix/FenixApplication.kt +++ b/app/src/main/java/org/mozilla/fenix/FenixApplication.kt @@ -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 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() diff --git a/app/src/main/java/org/mozilla/fenix/components/Analytics.kt b/app/src/main/java/org/mozilla/fenix/components/Analytics.kt index f10597b51..29b29d60a 100644 --- a/app/src/main/java/org/mozilla/fenix/components/Analytics.kt +++ b/app/src/main/java/org/mozilla/fenix/components/Analytics.kt @@ -19,6 +19,7 @@ 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 @@ -26,6 +27,7 @@ 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 ) { diff --git a/app/src/main/java/org/mozilla/fenix/components/BackgroundServices.kt b/app/src/main/java/org/mozilla/fenix/components/BackgroundServices.kt index 218ebe2c0..80a90e00c 100644 --- a/app/src/main/java/org/mozilla/fenix/components/BackgroundServices.kt +++ b/app/src/main/java/org/mozilla/fenix/components/BackgroundServices.kt @@ -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, diff --git a/app/src/main/java/org/mozilla/fenix/components/Components.kt b/app/src/main/java/org/mozilla/fenix/components/Components.kt index 1c5c8a843..beb850b7e 100644 --- a/app/src/main/java/org/mozilla/fenix/components/Components.kt +++ b/app/src/main/java/org/mozilla/fenix/components/Components.kt @@ -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) } diff --git a/app/src/main/java/org/mozilla/fenix/components/Core.kt b/app/src/main/java/org/mozilla/fenix/components/Core.kt index 8f9385879..98d8f3b85 100644 --- a/app/src/main/java/org/mozilla/fenix/components/Core.kt +++ b/app/src/main/java/org/mozilla/fenix/components/Core.kt @@ -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 @@ -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 { diff --git a/app/src/main/java/org/mozilla/fenix/components/FenixSnackbar.kt b/app/src/main/java/org/mozilla/fenix/components/FenixSnackbar.kt index 36dac6511..487838ad1 100644 --- a/app/src/main/java/org/mozilla/fenix/components/FenixSnackbar.kt +++ b/app/src/main/java/org/mozilla/fenix/components/FenixSnackbar.kt @@ -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, diff --git a/app/src/main/java/org/mozilla/fenix/components/FindInPageIntegration.kt b/app/src/main/java/org/mozilla/fenix/components/FindInPageIntegration.kt index 84bcd1f0c..601874c55 100644 --- a/app/src/main/java/org/mozilla/fenix/components/FindInPageIntegration.kt +++ b/app/src/main/java/org/mozilla/fenix/components/FindInPageIntegration.kt @@ -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, diff --git a/app/src/main/java/org/mozilla/fenix/components/Search.kt b/app/src/main/java/org/mozilla/fenix/components/Search.kt index 7746b1db2..081d60802 100644 --- a/app/src/main/java/org/mozilla/fenix/components/Search.kt +++ b/app/src/main/java/org/mozilla/fenix/components/Search.kt @@ -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) { /** diff --git a/app/src/main/java/org/mozilla/fenix/components/Services.kt b/app/src/main/java/org/mozilla/fenix/components/Services.kt index 646e559f2..64ab5db41 100644 --- a/app/src/main/java/org/mozilla/fenix/components/Services.kt +++ b/app/src/main/java/org/mozilla/fenix/components/Services.kt @@ -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 diff --git a/app/src/main/java/org/mozilla/fenix/components/Storage.kt b/app/src/main/java/org/mozilla/fenix/components/Storage.kt index 7c257687a..1a4f9b308 100644 --- a/app/src/main/java/org/mozilla/fenix/components/Storage.kt +++ b/app/src/main/java/org/mozilla/fenix/components/Storage.kt @@ -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 { diff --git a/app/src/main/java/org/mozilla/fenix/components/UseCases.kt b/app/src/main/java/org/mozilla/fenix/components/UseCases.kt index f25831aa4..46b643711 100644 --- a/app/src/main/java/org/mozilla/fenix/components/UseCases.kt +++ b/app/src/main/java/org/mozilla/fenix/components/UseCases.kt @@ -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, diff --git a/app/src/main/java/org/mozilla/fenix/components/Utilities.kt b/app/src/main/java/org/mozilla/fenix/components/Utilities.kt index fcf34d5c4..f7051c6e0 100644 --- a/app/src/main/java/org/mozilla/fenix/components/Utilities.kt +++ b/app/src/main/java/org/mozilla/fenix/components/Utilities.kt @@ -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, diff --git a/app/src/main/java/org/mozilla/fenix/library/bookmarks/BookmarkFragment.kt b/app/src/main/java/org/mozilla/fenix/library/bookmarks/BookmarkFragment.kt index 9aeec943b..824e7a1be 100644 --- a/app/src/main/java/org/mozilla/fenix/library/bookmarks/BookmarkFragment.kt +++ b/app/src/main/java/org/mozilla/fenix/library/bookmarks/BookmarkFragment.kt @@ -58,8 +58,8 @@ 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 || @@ -67,6 +67,7 @@ class BookmarkFragment : Fragment(), CoroutineScope, BackHandler, AccountObserve ) getManagedEmitter().onNext(BookmarkChange.ClearSelection) } + lateinit var initialJob: Job override val coroutineContext: CoroutineContext get() = Main + job @@ -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) { @@ -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 = getSelectedBookmarks(), diff --git a/app/src/main/java/org/mozilla/fenix/library/bookmarks/BookmarkUIView.kt b/app/src/main/java/org/mozilla/fenix/library/bookmarks/BookmarkUIView.kt index 73ee420d0..357d27298 100644 --- a/app/src/main/java/org/mozilla/fenix/library/bookmarks/BookmarkUIView.kt +++ b/app/src/main/java/org/mozilla/fenix/library/bookmarks/BookmarkUIView.kt @@ -92,23 +92,24 @@ class BookmarkUIView( fun getSelected(): Set = bookmarkAdapter.selected private fun setToolbarColors(foreground: Int, background: Int) { - val toolbar = (activity as AppCompatActivity).findViewById(R.id.navigationToolbar) + val toolbar = activity?.findViewById(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, diff --git a/app/src/test/java/org/mozilla/fenix/TestApplication.kt b/app/src/test/java/org/mozilla/fenix/TestApplication.kt new file mode 100644 index 000000000..a818b4e05 --- /dev/null +++ b/app/src/test/java/org/mozilla/fenix/TestApplication.kt @@ -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() { + } +} diff --git a/app/src/test/java/org/mozilla/fenix/components/TestBackgroundServices.kt b/app/src/test/java/org/mozilla/fenix/components/TestBackgroundServices.kt new file mode 100644 index 000000000..89be247a4 --- /dev/null +++ b/app/src/test/java/org/mozilla/fenix/components/TestBackgroundServices.kt @@ -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("") +} diff --git a/app/src/test/java/org/mozilla/fenix/components/TestComponents.kt b/app/src/test/java/org/mozilla/fenix/components/TestComponents.kt new file mode 100644 index 000000000..63bc9c3b5 --- /dev/null +++ b/app/src/test/java/org/mozilla/fenix/components/TestComponents.kt @@ -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(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) } +} \ No newline at end of file diff --git a/app/src/test/java/org/mozilla/fenix/components/TestCore.kt b/app/src/test/java/org/mozilla/fenix/components/TestCore.kt new file mode 100644 index 000000000..53c9b65f7 --- /dev/null +++ b/app/src/test/java/org/mozilla/fenix/components/TestCore.kt @@ -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(relaxed = true) + override val engine = mockk(relaxed = true) + override val sessionManager = SessionManager(engine) +} diff --git a/app/src/test/java/org/mozilla/fenix/components/metrics/ActivationPingTest.kt b/app/src/test/java/org/mozilla/fenix/components/metrics/ActivationPingTest.kt index 8c37c3187..449f29fac 100644 --- a/app/src/test/java/org/mozilla/fenix/components/metrics/ActivationPingTest.kt +++ b/app/src/test/java/org/mozilla/fenix/components/metrics/ActivationPingTest.kt @@ -16,11 +16,11 @@ import io.mockk.mockkStatic import io.mockk.slot import io.mockk.spyk import io.mockk.verify -import org.junit.jupiter.api.Test +import junit.framework.Assert.assertEquals +import junit.framework.Assert.assertNull import kotlinx.coroutines.runBlocking -import org.junit.jupiter.api.Assertions.assertEquals -import org.junit.jupiter.api.Assertions.assertNull +import org.junit.Test import org.mockito.ArgumentMatchers.any import org.mockito.ArgumentMatchers.anyString import java.io.IOException diff --git a/app/src/test/java/org/mozilla/fenix/library/bookmarks/BookmarkAdapterTest.kt b/app/src/test/java/org/mozilla/fenix/library/bookmarks/BookmarkAdapterTest.kt index 5ca855391..6d7c43e55 100644 --- a/app/src/test/java/org/mozilla/fenix/library/bookmarks/BookmarkAdapterTest.kt +++ b/app/src/test/java/org/mozilla/fenix/library/bookmarks/BookmarkAdapterTest.kt @@ -14,8 +14,8 @@ import io.reactivex.Observer import io.reactivex.observers.TestObserver import mozilla.components.concept.storage.BookmarkNode import mozilla.components.concept.storage.BookmarkNodeType -import org.junit.jupiter.api.BeforeEach -import org.junit.jupiter.api.Test +import org.junit.Before +import org.junit.Test import org.mozilla.fenix.TestUtils.setRxSchedulers internal class BookmarkAdapterTest { @@ -23,7 +23,7 @@ internal class BookmarkAdapterTest { private lateinit var bookmarkAdapter: BookmarkAdapter private lateinit var emitter: Observer - @BeforeEach + @Before fun setup() { setRxSchedulers() emitter = TestObserver() diff --git a/app/src/test/java/org/mozilla/fenix/library/bookmarks/BookmarkComponentTest.kt b/app/src/test/java/org/mozilla/fenix/library/bookmarks/BookmarkComponentTest.kt index eff1f6ba3..04cc80061 100644 --- a/app/src/test/java/org/mozilla/fenix/library/bookmarks/BookmarkComponentTest.kt +++ b/app/src/test/java/org/mozilla/fenix/library/bookmarks/BookmarkComponentTest.kt @@ -13,8 +13,8 @@ import io.reactivex.observers.TestObserver import mozilla.appservices.places.BookmarkRoot import mozilla.components.concept.storage.BookmarkNode import mozilla.components.concept.storage.BookmarkNodeType -import org.junit.jupiter.api.BeforeEach -import org.junit.jupiter.api.Test +import org.junit.Before +import org.junit.Test import org.mozilla.fenix.TestUtils import org.mozilla.fenix.mvi.ActionBusFactory import org.mozilla.fenix.mvi.UIView @@ -26,7 +26,7 @@ class BookmarkComponentTest { private lateinit var bookmarkObserver: TestObserver private lateinit var emitter: Observer - @BeforeEach + @Before fun setup() { MockKAnnotations.init(this) TestUtils.setRxSchedulers() diff --git a/app/src/test/java/org/mozilla/fenix/library/bookmarks/BookmarkFragmentTest.kt b/app/src/test/java/org/mozilla/fenix/library/bookmarks/BookmarkFragmentTest.kt new file mode 100644 index 000000000..491c21ec2 --- /dev/null +++ b/app/src/test/java/org/mozilla/fenix/library/bookmarks/BookmarkFragmentTest.kt @@ -0,0 +1,60 @@ +/* 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.library.bookmarks + +import androidx.fragment.app.testing.FragmentScenario +import androidx.fragment.app.testing.launchFragmentInContainer +import androidx.navigation.NavController +import androidx.navigation.Navigation +import io.mockk.Runs +import io.mockk.every +import io.mockk.just +import io.mockk.mockk +import kotlinx.coroutines.ObsoleteCoroutinesApi +import mozilla.appservices.places.BookmarkRoot +import org.junit.Assert.assertEquals +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mozilla.fenix.R +import org.mozilla.fenix.TestApplication +import org.mozilla.fenix.TestUtils +import org.robolectric.RobolectricTestRunner +import org.robolectric.annotation.Config + +@ObsoleteCoroutinesApi +@RunWith(RobolectricTestRunner::class) +@Config(application = TestApplication::class) +class BookmarkFragmentTest { + + private lateinit var scenario: FragmentScenario + + @Before + fun setup() { + TestUtils.setRxSchedulers() + + val mockNavController = mockk() + every { mockNavController.addOnDestinationChangedListener(any()) } just Runs + + val args = BookmarkFragmentArgs(BookmarkRoot.Mobile.id).toBundle() + scenario = + launchFragmentInContainer(fragmentArgs = args, themeResId = R.style.NormalTheme) { + BookmarkFragment().also { fragment -> + fragment.viewLifecycleOwnerLiveData.observeForever { + if (it != null) { + Navigation.setViewNavController(fragment.requireView(), mockNavController) + } + } + } + } + } + + @Test + fun `test initial bookmarks fragment ui`() { + scenario.onFragment { fragment -> + assertEquals(fragment.getString(R.string.library_bookmarks), fragment.activity?.title) + } + } +} diff --git a/app/src/test/java/org/mozilla/fenix/library/history/HistoryComponentTest.kt b/app/src/test/java/org/mozilla/fenix/library/history/HistoryComponentTest.kt index edb6dc064..c69f20d96 100644 --- a/app/src/test/java/org/mozilla/fenix/library/history/HistoryComponentTest.kt +++ b/app/src/test/java/org/mozilla/fenix/library/history/HistoryComponentTest.kt @@ -10,8 +10,8 @@ import io.mockk.mockk import io.mockk.spyk import io.reactivex.Observer import io.reactivex.observers.TestObserver -import org.junit.jupiter.api.BeforeEach -import org.junit.jupiter.api.Test +import org.junit.Before +import org.junit.Test import org.mozilla.fenix.TestUtils.bus import org.mozilla.fenix.TestUtils.owner import org.mozilla.fenix.TestUtils.setRxSchedulers @@ -25,7 +25,7 @@ class HistoryComponentTest { private lateinit var historyObserver: TestObserver private lateinit var emitter: Observer - @BeforeEach + @Before fun setup() { MockKAnnotations.init(this) setRxSchedulers() diff --git a/architecture/src/main/java/org/mozilla/fenix/test/Mockable.kt b/architecture/src/main/java/org/mozilla/fenix/test/Mockable.kt deleted file mode 100644 index d98f5dd0a..000000000 --- a/architecture/src/main/java/org/mozilla/fenix/test/Mockable.kt +++ /dev/null @@ -1,7 +0,0 @@ -/* 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.test - -annotation class Mockable \ No newline at end of file diff --git a/architecture/src/main/java/org/mozilla/fenix/test/OpenClass.kt b/architecture/src/main/java/org/mozilla/fenix/test/OpenClass.kt new file mode 100644 index 000000000..2a8423a72 --- /dev/null +++ b/architecture/src/main/java/org/mozilla/fenix/test/OpenClass.kt @@ -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.test + +/** + * Annotate a class with [OpenClass] to open a class for mocking purposes while keeping it final in release builds + */ +@Target(AnnotationTarget.ANNOTATION_CLASS) +annotation class OpenClass + +/** + * Annotate a class with [Mockable] to make it extensible in debug builds + */ +@OpenClass +@Target(AnnotationTarget.CLASS) +annotation class Mockable diff --git a/buildSrc/src/main/java/Dependencies.kt b/buildSrc/src/main/java/Dependencies.kt index 0ada9a51b..b0570db91 100644 --- a/buildSrc/src/main/java/Dependencies.kt +++ b/buildSrc/src/main/java/Dependencies.kt @@ -23,15 +23,17 @@ private object Versions { const val androidx_fragment = "1.1.0-alpha07" const val androidx_navigation = "2.1.0-alpha02" const val androidx_recyclerview = "1.1.0-alpha04" + const val androidx_testing = "1.1.0-alpha07" const val appservices_gradle_plugin = "0.4.4" const val mozilla_android_components = "0.52.0-SNAPSHOT" + const val mozilla_appservices = "0.27.0" const val autodispose = "1.1.0" const val adjust = "4.11.4" const val installreferrer = "1.0" - const val junit_jupiter = "5.3.2" + const val junit = "4.12" const val mockito = "2.23.0" const val mockk = "1.9.kotlin12" const val glide = "4.9.0" @@ -44,7 +46,7 @@ private object Versions { const val tools_test_rules = "1.1.1" const val tools_test_runner = "1.1.1" const val uiautomator = "2.1.3" - const val test_tools = "1.0.2" + const val robolectric = "4.2" const val google_ads_id_version = "16.0.0" } @@ -146,10 +148,7 @@ object Deps { const val adjust = "com.adjust.sdk:adjust-android:${Versions.adjust}" const val installreferrer = "com.android.installreferrer:installreferrer:${Versions.installreferrer}" - const val junit_jupiter_api = "org.junit.jupiter:junit-jupiter-api:${Versions.junit_jupiter}" - const val junit_jupiter_params = "org.junit.jupiter:junit-jupiter-params:${Versions.junit_jupiter}" - const val junit_jupiter_engine = "org.junit.jupiter:junit-jupiter-engine:${Versions.junit_jupiter}" - + 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}" @@ -167,6 +166,10 @@ object Deps { const val tools_test_rules = "com.android.support.test:rules:${Versions.tools_test_rules}" const val tools_test_runner = "com.android.support.test:runner:${Versions.tools_test_runner}" const val uiautomator = "com.android.support.test.uiautomator:uiautomator-v18:${Versions.uiautomator}" + const val robolectric = "org.robolectric:robolectric:${Versions.robolectric}" + const val fragment_testing = "androidx.fragment:fragment-testing:${Versions.androidx_testing}" + const val megazord_forUnitTests = "org.mozilla.appservices:fenix-megazord-forUnitTests:${Versions.mozilla_appservices}" + const val places_forUnitTests = "org.mozilla.appservices:places-forUnitTests:${Versions.mozilla_appservices}" const val google_ads_id = "com.google.android.gms:play-services-ads-identifier:${Versions.google_ads_id_version}" } diff --git a/gradle.properties b/gradle.properties index e13e313e2..f0221c16b 100644 --- a/gradle.properties +++ b/gradle.properties @@ -16,4 +16,5 @@ kotlin.code.style=official android.useAndroidX=true android.enableJetifier=true android.enableR8=true -android.enableR8.fullMode=true \ No newline at end of file +android.enableR8.fullMode=true +android.enableUnitTestBinaryResources=true \ No newline at end of file