Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Migrate Instrumentation tests to Robolectric #10

Merged
merged 8 commits into from
May 7, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ jobs:
arguments: testDebug --stacktrace

android_tests:
if: ${{ false }} # Disable checking Instrumentation tests
needs: [ ktlint, build ]
name: Run Android Tests
runs-on: macos-latest
Expand Down
1 change: 1 addition & 0 deletions androidTest-shared/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -38,4 +38,5 @@ dependencies {
implementation(Libs.testJUnit)
implementation(Libs.testAndroidXJUnit)
implementation(Libs.testKotlinCoroutines)
implementation(Libs.testAndroidxCoreTesting)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package dev.mslalith.focuslauncher.androidtest.shared

import androidx.arch.core.executor.testing.InstantTaskExecutorRule
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.runTest
import org.junit.Rule

@OptIn(ExperimentalCoroutinesApi::class)
open class CoroutineTest {

@get:Rule
val instantExecutorRule = InstantTaskExecutorRule()

@get:Rule
val coroutineTestRule = MainCoroutineRule()

protected fun runCoroutineTest(
testBody: suspend TestScope.() -> Unit
) = runTest(testBody = testBody)
}
12 changes: 7 additions & 5 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,13 @@ android {
lint {
error.add("VisibleForTests")
}
testOptions {
unitTests.all {
it.extensions.configure(kotlinx.kover.api.KoverTaskExtension::class) {
isDisabled = it.name != "testDebugUnitTest"
}
}
}
}

dependencies {
Expand All @@ -73,11 +80,6 @@ dependencies {
composeInterop()

hilt()
room()
dataStore()
accompanist()
retrofit()

thirdPartyLibs()
testLibs()
}
89 changes: 38 additions & 51 deletions build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import com.github.benmanes.gradle.versions.updates.DependencyUpdatesTask
import com.github.benmanes.gradle.versions.updates.gradle.GradleReleaseChannel
import com.vanniktech.android.junit.jacoco.JunitJacocoExtension
import java.nio.file.Files
import java.nio.file.Paths
import java.nio.file.attribute.PosixFilePermission

// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
Expand All @@ -12,76 +14,43 @@ buildscript {
classpath(Libs.buildToolsGradle)
classpath(Libs.buildToolsKotlinGradlePlugin)
classpath(Libs.buildToolsHiltAndroidGradlePlugin)
classpath(Libs.buildToolsJacocoPlugin)
classpath(Libs.buildToolsKotlinxKover)
}
}

apply(plugin = "com.vanniktech.android.junit.jacoco")
apply(plugin = "kover")

// ktlint-gradle
plugins {
id("org.jlleitschuh.gradle.ktlint") version "10.2.1"
id("com.github.ben-manes.versions") version "0.42.0"
id("org.jetbrains.kotlinx.kover") version "0.5.0"
}

allprojects {
apply(plugin = "org.jlleitschuh.gradle.ktlint")
}

tasks.register("clean", Delete::class) {
delete(rootProject.buildDir)
kover {
isDisabled = false
coverageEngine.set(kotlinx.kover.api.CoverageEngine.INTELLIJ)
}

// Configure Jacoco
configure<JunitJacocoExtension> {
jacocoVersion = "0.8.8"
includeNoLocationClasses = true
includeInstrumentationCoverageInMergedReport = true
tasks.koverMergedHtmlReport {
isEnabled = true
htmlReportDir.set(layout.buildDirectory.dir("kover-report/html-report"))
excludes = listOf(
"**/databinding/*Binding.*",
"**/R.class",
"**/R$*.class",
"**/BuildConfig.*",
"**/Manifest*.*",
"**/*Test*.*",
"android/**/*.*",
"**/*\$ViewInjector*.*",
"**/*\$ViewBinder*.*",
"**/Lambda$*.class",
"**/Lambda.class",
"**/*Lambda.class",
"**/*Lambda*.class",
"**/*_MembersInjector.class",
"**/Dagger*Component*.*",
"**/*Module_*Factory.class",
"**/di/module/*",
"**/*_Factory*.*",
"**/*Module*.*",
"**/*Dagger*.*",
"**/*Hilt*.*",
"**/*MapperImpl*.*",
"**/*\$ViewInjector*.*",
"**/*\$ViewBinder*.*",
"**/BuildConfig.*",
"**/*Component*.*",
"**/*BR*.*",
"**/Manifest*.*",
"**/*\$Lambda$*.*",
"**/*Companion*.*",
"**/*Module*.*",
"**/*Dagger*.*",
"**/*Hilt*.*",
"**/*MembersInjector*.*",
"**/*_MembersInjector.class",
"**/*_Factory*.*",
"**/*_Provide*Factory*.*",
"**/*Extensions*.*",

"**/*dagger.hilt**/**.*",
"**hilt_aggregated_deps**"
"jdk.internal.*",
"dagger.hilt.internal.aggregatedroot.codegen.**",
"hilt_aggregated_deps.**",
"dev.mslalith.focuslauncher.**.*_Factory"
)
}

tasks.register("clean", Delete::class) {
delete(rootProject.buildDir)
}

/*
check for dependency updates by running
./gradlew dependencyUpdates
Expand All @@ -95,3 +64,21 @@ tasks.named<DependencyUpdatesTask>("dependencyUpdates").configure {
outputDir = "build/dependencyUpdates"
reportfileName = "dependency_update_report"
}

// Create a task to copy Git hooks from /scripts to .git/hooks path
val installGitHooks by tasks.creating(Copy::class) {
from(layout.projectDirectory.file("scripts/pre-push"))
val toDir = layout.projectDirectory.dir(".git/hooks")
val toFile = toDir.file("pre-push").asFile
val toFilePath = Paths.get(toFile.absolutePath)
into(toDir)

doLast {
val perms = Files.getPosixFilePermissions(toFilePath)
perms.add(PosixFilePermission.OWNER_EXECUTE)
Files.setPosixFilePermissions(toFilePath, perms)
}
}

// Register the Git task to run at beginning
tasks.getByPath(":app:preBuild").dependsOn(installGitHooks)
4 changes: 0 additions & 4 deletions buildSrc/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,3 @@ plugins {
repositories {
gradlePluginPortal()
}

tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile> {
kotlinOptions.jvmTarget = JavaVersion.VERSION_11.toString()
}
10 changes: 9 additions & 1 deletion buildSrc/src/main/kotlin/Libs.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ object Libs {
const val buildToolsGradle = "com.android.tools.build:gradle:${Versions.GRADLE}"
const val buildToolsKotlinGradlePlugin = "org.jetbrains.kotlin:kotlin-gradle-plugin:${Versions.KOTLIN}"
const val buildToolsHiltAndroidGradlePlugin = "com.google.dagger:hilt-android-gradle-plugin:${Versions.HILT}"
const val buildToolsJacocoPlugin = "com.vanniktech:gradle-android-junit-jacoco-plugin:${Versions.JACOCO_PLUGIN}"
const val buildToolsKotlinxKover = "org.jetbrains.kotlinx:kover:${Versions.KOTLINX_KOVER}"

const val coreKtx = "androidx.core:core-ktx:${Versions.KOTLIN_CORE_KTX}"
const val kotlinxDateTime = "org.jetbrains.kotlinx:kotlinx-datetime:${Versions.KOTLINX_DATETIME}"
Expand Down Expand Up @@ -53,6 +53,9 @@ object Libs {
const val testComposeJUnit = "androidx.compose.ui:ui-test-junit4:${Versions.COMPOSE}"
const val testKotlinCoroutines = "org.jetbrains.kotlinx:kotlinx-coroutines-test:${Versions.TEST_KOTLIN_COROUTINES}"
const val testTurbine = "app.cash.turbine:turbine:${Versions.TEST_TURBINE}"
const val testAndroidxCoreKtx = "androidx.test:core-ktx:${Versions.TEST_ANDROIDX_CORE_KTX}"
const val testAndroidxCoreTesting = "androidx.arch.core:core-testing:${Versions.TEST_ANDROIDX_CORE_TESTING}"
const val testRobolectric = "org.robolectric:robolectric:${Versions.TEST_ROBOLECTRIC}"
}

/**
Expand Down Expand Up @@ -146,6 +149,11 @@ fun DependencyHandler.junit(includeAndroid: Boolean) {
}
}

fun DependencyHandler.robolectric() {
testImplementation(Libs.testAndroidxCoreKtx)
testImplementation(Libs.testRobolectric)
}

fun DependencyHandler.truth(includeAndroid: Boolean) {
testImplementation(Libs.testTruth)
if (includeAndroid) androidTestImplementation(Libs.testTruth)
Expand Down
5 changes: 4 additions & 1 deletion buildSrc/src/main/kotlin/Versions.kt
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
object Versions {
const val KOTLIN = "1.6.10"
const val GRADLE = "7.1.3"
const val KOTLINX_KOVER = "0.5.0"

const val KOTLIN_CORE_KTX = "1.8.0-alpha07"
const val KOTLINX_DATETIME = "0.3.2"
Expand All @@ -26,7 +27,6 @@ object Versions {
const val RETROFIT = "2.9.0"
const val ACCOMPANIST = "0.24.6-alpha"

const val JACOCO_PLUGIN = "0.16.0"
const val THIRD_SUNCALC = "3.5"

const val TEST_JUNIT = "4.13.2"
Expand All @@ -35,4 +35,7 @@ object Versions {
const val TEST_ANDROIDX_ESPRESSO = "3.5.0-alpha05"
const val TEST_KOTLIN_COROUTINES = "1.6.1"
const val TEST_TURBINE = "0.7.0"
const val TEST_ROBOLECTRIC = "4.8"
const val TEST_ANDROIDX_CORE_KTX = "1.4.0"
const val TEST_ANDROIDX_CORE_TESTING = "2.1.0"
}
18 changes: 13 additions & 5 deletions data/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -48,10 +48,17 @@ android {
lint {
error.add("VisibleForTests")
}
testOptions {
unitTests.all {
it.extensions.configure(kotlinx.kover.api.KoverTaskExtension::class) {
isDisabled = it.name != "testDebugUnitTest"
}
}
}
}

dependencies {
androidTestImplementation(project(mapOf("path" to ":androidTest-shared")))
testImplementation(project(mapOf("path" to ":androidTest-shared")))

androidxCoreKtx()
hiltAndroid()
Expand All @@ -63,8 +70,9 @@ dependencies {
implementation(Libs.googlePlayCoreKtx)
implementation(Libs.thirdSunCalc)

junit(includeAndroid = true)
truth(includeAndroid = true)
kotlinxCoroutinesTest(includeAndroid = true)
turbine(includeAndroid = true)
junit(includeAndroid = false)
truth(includeAndroid = false)
kotlinxCoroutinesTest(includeAndroid = false)
turbine(includeAndroid = false)
robolectric()
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ interface HiddenAppsDao {
@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun hideApp(hiddenAppRoom: HiddenAppRoom)

@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun hideApps(hiddenAppRoomList: List<HiddenAppRoom>)

@Delete
suspend fun unHideApp(hiddenAppRoom: HiddenAppRoom)
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,11 @@ class FavoritesRepo @Inject constructor(
favoriteAppsDao.addFavorite(favoriteAppRoom)
}

suspend fun addToFavorites(apps: List<App>) {
val favoriteAppRoomList = apps.map(favoriteToRoomMapper::toEntity)
favoriteAppsDao.addFavorites(favoriteAppRoomList)
}

suspend fun reorderFavorite(app: App, withApp: App) {
val apps = favoriteAppsDao.getFavoriteAppsFlow().first().toMutableList()
val appIndex = apps.indexOfFirst { it.packageName == app.packageName }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,11 @@ class HiddenAppsRepo @Inject constructor(
hiddenAppsDao.hideApp(hiddenToRoomMapper.toEntity(app))
}

suspend fun addToHiddenApps(apps: List<App>) {
val hiddenAppRoomList = apps.map(hiddenToRoomMapper::toEntity)
hiddenAppsDao.hideApps(hiddenAppRoomList)
}

suspend fun removeFromHiddenApps(packageName: String) {
val appRoom = appsDao.getAppBy(packageName) ?: throw IllegalStateException("$packageName app was not found in Database")
val app = appToRoomMapper.fromEntity(appRoom)
Expand Down