diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 6691e7d..6b770da 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -2,7 +2,7 @@ import de.fayard.refreshVersions.core.versionFor plugins { id("com.android.application") - id("com.dicedmelon.gradle.jacoco-android") + id("de.mannodermaus.android-junit5") kotlin("android") kotlin("kapt") id("dagger.hilt.android.plugin") @@ -33,6 +33,10 @@ android { versionName = Apps.versionName testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" + testInstrumentationRunnerArguments += mapOf( + "runnerBuilder" to "de.mannodermaus.junit5.AndroidJUnit5Builder", + ) + vectorDrawables { useSupportLibrary = true } @@ -119,6 +123,9 @@ dependencies { testImplementation(Libs.junit_jupiter_api) testImplementation(Libs.junit_jupiter_engine) + androidTestImplementation(Libs.junit_jupiter_api) + androidTestImplementation(Libs.junit_jupiter_engine) + implementation(Libs.ksp_api) implementation(Libs.lottie_compose) @@ -137,4 +144,8 @@ dependencies { testImplementation(Libs.turbine) androidTestImplementation(Libs.turbine) + + androidTestImplementation(Libs.junit5_android_test_core) + testImplementation(Libs.junit5_android_test_core) + androidTestRuntimeOnly(Libs.junit5_android_test_runner) } \ No newline at end of file diff --git a/app/src/androidTest/java/com/ericampire/android/androidstudycase/ExampleInstrumentedTest.kt b/app/src/androidTest/java/com/ericampire/android/androidstudycase/ExampleInstrumentedTest.kt deleted file mode 100644 index 3807a45..0000000 --- a/app/src/androidTest/java/com/ericampire/android/androidstudycase/ExampleInstrumentedTest.kt +++ /dev/null @@ -1,24 +0,0 @@ -package com.ericampire.android.androidstudycase - -import androidx.test.platform.app.InstrumentationRegistry -import androidx.test.ext.junit.runners.AndroidJUnit4 - -import org.junit.Test -import org.junit.runner.RunWith - -import org.junit.Assert.* - -/** - * Instrumented test, which will execute on an Android device. - * - * See [testing documentation](http://d.android.com/tools/testing). - */ -@RunWith(AndroidJUnit4::class) -class ExampleInstrumentedTest { - @Test - fun useAppContext() { - // Context of the app under test. - val appContext = InstrumentationRegistry.getInstrumentation().targetContext - assertEquals("com.ericampire.android.androidstudycase", appContext.packageName) - } -} \ No newline at end of file diff --git a/app/src/androidTest/java/com/ericampire/android/androidstudycase/presentation/ExploreScreenTest.kt b/app/src/androidTest/java/com/ericampire/android/androidstudycase/presentation/ExploreScreenTest.kt index 278b2ee..7859f1c 100644 --- a/app/src/androidTest/java/com/ericampire/android/androidstudycase/presentation/ExploreScreenTest.kt +++ b/app/src/androidTest/java/com/ericampire/android/androidstudycase/presentation/ExploreScreenTest.kt @@ -1,20 +1,17 @@ package com.ericampire.android.androidstudycase.presentation import androidx.compose.material.ExperimentalMaterialApi +import androidx.compose.ui.test.assertIsSelected import androidx.compose.ui.test.junit4.createAndroidComposeRule +import androidx.compose.ui.test.onNodeWithText +import androidx.compose.ui.test.performClick import androidx.navigation.compose.rememberNavController import com.ericampire.android.androidstudycase.MainActivity -import com.ericampire.android.androidstudycase.presentation.screen.explore.business.ExploreAction -import com.ericampire.android.androidstudycase.presentation.screen.explore.business.ExploreViewModel import com.ericampire.android.androidstudycase.presentation.screen.explore.ui.ExploreScreen -import com.ericampire.android.androidstudycase.util.PreviewData import com.google.accompanist.pager.ExperimentalPagerApi +import org.junit.Ignore import org.junit.Rule import org.junit.Test -import org.mockito.kotlin.any -import org.mockito.kotlin.doReturn -import org.mockito.kotlin.mock -import org.mockito.kotlin.verify @ExperimentalMaterialApi @ExperimentalPagerApi @@ -24,17 +21,15 @@ class ExploreScreenTest { val composeTestRule = createAndroidComposeRule() @Test + @Ignore fun whenSubmitActionShouldReturnData() { - val exploreViewModel = mock { - on { submitAction(ExploreAction.FindPopularFile) } - doReturn(PreviewData.Lottiefile.data) - } + composeTestRule.setContent { - ExploreScreen( - navController = rememberNavController(), - viewModel = exploreViewModel - ) + ExploreScreen(navController = rememberNavController()) } - verify(exploreViewModel).submitAction(any()) + + composeTestRule.onNodeWithText("Recent").performClick().assertIsSelected() + composeTestRule.onNodeWithText("Featured").performClick().assertIsSelected() + composeTestRule.onNodeWithText("Popular").performClick().assertIsSelected() } } \ No newline at end of file diff --git a/app/src/androidTest/java/com/ericampire/android/androidstudycase/room/AnimationDoaTest.kt b/app/src/androidTest/java/com/ericampire/android/androidstudycase/room/AnimationDoaTest.kt new file mode 100644 index 0000000..c30a6ec --- /dev/null +++ b/app/src/androidTest/java/com/ericampire/android/androidstudycase/room/AnimationDoaTest.kt @@ -0,0 +1,32 @@ +package com.ericampire.android.androidstudycase.room + +import app.cash.turbine.test +import com.ericampire.android.androidstudycase.data.room.LottieFilesDao +import com.ericampire.android.androidstudycase.room.common.DatabaseTest +import com.ericampire.android.androidstudycase.util.PreviewData +import kotlinx.coroutines.runBlocking +import org.junit.jupiter.api.Assertions +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import kotlin.time.ExperimentalTime + +@ExperimentalTime +class AnimationDoaTest : DatabaseTest() { + + private lateinit var animationDao: LottieFilesDao + + @BeforeEach + fun setup() { + animationDao = db.lottieFileDao + } + + + @Test + fun saveAnimation() = runBlocking { + val animation = PreviewData.Lottiefile.data.first().copy(type = "recent") + animationDao.save(animation) + animationDao.findByType("recent").test { + Assertions.assertEquals(awaitItem().first(), animation) + } + } +} \ No newline at end of file diff --git a/app/src/androidTest/java/com/ericampire/android/androidstudycase/room/AnimatorDaoTest.kt b/app/src/androidTest/java/com/ericampire/android/androidstudycase/room/AnimatorDaoTest.kt new file mode 100644 index 0000000..c926104 --- /dev/null +++ b/app/src/androidTest/java/com/ericampire/android/androidstudycase/room/AnimatorDaoTest.kt @@ -0,0 +1,31 @@ +package com.ericampire.android.androidstudycase.room + +import app.cash.turbine.test +import com.ericampire.android.androidstudycase.data.room.AnimatorDao +import com.ericampire.android.androidstudycase.room.common.DatabaseTest +import com.ericampire.android.androidstudycase.util.PreviewData +import kotlinx.coroutines.runBlocking +import org.junit.jupiter.api.Assertions +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import kotlin.time.ExperimentalTime + +@ExperimentalTime +class AnimatorDoaTest : DatabaseTest() { + + private lateinit var animatorDao: AnimatorDao + + @BeforeEach + fun setup() { + animatorDao = db.animatorDao + } + + @Test + fun saveAnimator() = runBlocking { + val testData = PreviewData.Animator.data.first().copy(id = 1) + animatorDao.save(testData) + animatorDao.findAll().test { + Assertions.assertEquals(awaitItem().first(), testData) + } + } +} \ No newline at end of file diff --git a/app/src/androidTest/java/com/ericampire/android/androidstudycase/room/BlogDaoTest.kt b/app/src/androidTest/java/com/ericampire/android/androidstudycase/room/BlogDaoTest.kt new file mode 100644 index 0000000..ebd7bda --- /dev/null +++ b/app/src/androidTest/java/com/ericampire/android/androidstudycase/room/BlogDaoTest.kt @@ -0,0 +1,31 @@ +package com.ericampire.android.androidstudycase.room + +import app.cash.turbine.test +import com.ericampire.android.androidstudycase.data.room.BlogDao +import com.ericampire.android.androidstudycase.room.common.DatabaseTest +import com.ericampire.android.androidstudycase.util.PreviewData +import kotlinx.coroutines.runBlocking +import org.junit.jupiter.api.Assertions +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import kotlin.time.ExperimentalTime + + +@ExperimentalTime +class BlogDoaTest : DatabaseTest() { + + private lateinit var blogDoa: BlogDao + + @BeforeEach + fun setup() { + blogDoa = db.blogDao + } + + @Test + fun saveBlog() = runBlocking { + blogDoa.save(PreviewData.Blog.data.first()) + blogDoa.findAll().test { + Assertions.assertEquals(awaitItem().first(), PreviewData.Blog.data.first()) + } + } +} \ No newline at end of file diff --git a/app/src/androidTest/java/com/ericampire/android/androidstudycase/room/UserDaoTest.kt b/app/src/androidTest/java/com/ericampire/android/androidstudycase/room/UserDaoTest.kt index 68e1ecf..538d277 100644 --- a/app/src/androidTest/java/com/ericampire/android/androidstudycase/room/UserDaoTest.kt +++ b/app/src/androidTest/java/com/ericampire/android/androidstudycase/room/UserDaoTest.kt @@ -1,64 +1,31 @@ package com.ericampire.android.androidstudycase.room -import android.content.Context -import androidx.room.Room -import androidx.test.core.app.ApplicationProvider -import androidx.test.ext.junit.runners.AndroidJUnit4 import app.cash.turbine.test -import com.ericampire.android.androidstudycase.app.room.AppDatabase import com.ericampire.android.androidstudycase.data.room.UserDao +import com.ericampire.android.androidstudycase.room.common.DatabaseTest import com.ericampire.android.androidstudycase.util.PreviewData import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.ExperimentalCoroutinesApi -import kotlinx.coroutines.test.* -import org.hamcrest.CoreMatchers.equalTo -import org.hamcrest.MatcherAssert.assertThat -import org.junit.After -import org.junit.Before -import org.junit.Ignore -import org.junit.Test -import org.junit.runner.RunWith -import java.io.IOException +import kotlinx.coroutines.runBlocking +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test import kotlin.time.ExperimentalTime -@RunWith(AndroidJUnit4::class) -@ExperimentalCoroutinesApi @ExperimentalTime -class UserDaoTest { - - private val testDispatcher = TestCoroutineDispatcher() - private val testScope = TestCoroutineScope(testDispatcher) +class UserDoaTest : DatabaseTest() { private lateinit var userDao: UserDao - private lateinit var db: AppDatabase - @Before - fun setupDispatcher() { - Dispatchers.setMain(testDispatcher) - } - - - @Before - fun createDb() { - val context = ApplicationProvider.getApplicationContext() - db = Room.inMemoryDatabaseBuilder(context, AppDatabase::class.java).build() + @BeforeEach + fun setup() { userDao = db.userDao } @Test - @Ignore - fun saveUser() = testScope.runBlockingTest { + fun saveUser() = runBlocking(Dispatchers.IO) { userDao.save(PreviewData.User.data.first()) userDao.findAll().test { - assertThat(awaitItem(), equalTo(PreviewData.User.data.first())) + assertEquals(awaitItem().first(), PreviewData.User.data.first()) } } - - @After - @Throws(IOException::class) - fun teardown() { - db.close() - Dispatchers.resetMain() - testDispatcher.cleanupTestCoroutines() - } } \ No newline at end of file diff --git a/app/src/androidTest/java/com/ericampire/android/androidstudycase/room/common/DatabaseTest.kt b/app/src/androidTest/java/com/ericampire/android/androidstudycase/room/common/DatabaseTest.kt new file mode 100644 index 0000000..5405eea --- /dev/null +++ b/app/src/androidTest/java/com/ericampire/android/androidstudycase/room/common/DatabaseTest.kt @@ -0,0 +1,24 @@ +package com.ericampire.android.androidstudycase.room.common + +import androidx.room.Room +import androidx.test.core.app.ApplicationProvider.getApplicationContext +import com.ericampire.android.androidstudycase.app.room.AppDatabase +import org.junit.jupiter.api.AfterEach +import org.junit.jupiter.api.BeforeEach + + +abstract class DatabaseTest { + lateinit var db: AppDatabase + + @BeforeEach + fun initDB() { + db = Room.inMemoryDatabaseBuilder(getApplicationContext(), AppDatabase::class.java) + .allowMainThreadQueries() + .build() + } + + @AfterEach + fun closeDB() { + db.close() + } +} \ No newline at end of file diff --git a/app/src/main/java/com/ericampire/android/androidstudycase/util/PreviewData.kt b/app/src/main/java/com/ericampire/android/androidstudycase/util/PreviewData.kt index fbbc1f4..ad93c86 100644 --- a/app/src/main/java/com/ericampire/android/androidstudycase/util/PreviewData.kt +++ b/app/src/main/java/com/ericampire/android/androidstudycase/util/PreviewData.kt @@ -15,21 +15,25 @@ object PreviewData { object Blog { val data = listOf( Blog( + id = 1, postedAt = "2021-07-08T00:00:00.000Z", imageUrl = "https://d3jl769oy69y7b.cloudfront.net/2021/07/Blog-Visual---The-Key-to-An-Immersive-UX_-Animation.png", title = "The Key to An Immersive UX: Animation" ), Blog( + id = 2, title = "LottieFiles Animations are accessible across 25,000+ everyday tools with the embed feature", postedAt = "2021-06-18T00:00:00.000Z", imageUrl = "https://d3jl769oy69y7b.cloudfront.net/2021/06/Embed-Blog-OG.png" ), Blog( + id = 3, postedAt = "2021-07-08T00:00:00.000Z", imageUrl = "https://d3jl769oy69y7b.cloudfront.net/2021/07/Blog-Visual---The-Key-to-An-Immersive-UX_-Animation.png", title = "The Key to An Immersive UX: Animation" ), Blog( + id = 4, title = "LottieFiles Animations are accessible across 25,000+ everyday tools with the embed feature", postedAt = "2021-06-18T00:00:00.000Z", imageUrl = "https://d3jl769oy69y7b.cloudfront.net/2021/06/Embed-Blog-OG.png" diff --git a/build.gradle.kts b/build.gradle.kts index 79c5ff9..7f42104 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -10,7 +10,7 @@ buildscript { dependencies { classpath(Libs.kotlin_gradle_plugin) classpath(Libs.gradle_plugin) - classpath("com.dicedmelon.gradle:jacoco-android:0.1.5") + classpath("de.mannodermaus.gradle.plugins:android-junit5:1.7.1.1") classpath(Libs.hilt_gradle_plugin) } } diff --git a/buildSrc/src/main/kotlin/Libs.kt b/buildSrc/src/main/kotlin/Libs.kt index 5c70fa2..2e48219 100644 --- a/buildSrc/src/main/kotlin/Libs.kt +++ b/buildSrc/src/main/kotlin/Libs.kt @@ -57,6 +57,7 @@ object Libs { const val hilt_gradle_plugin = "com.google.dagger:hilt-android-gradle-plugin:_" const val hilt_android = "com.google.dagger:hilt-android:_" + const val hilt_android_testing = "com.google.dagger:hilt-android-testing:_" const val hilt_android_compiler = "com.google.dagger:hilt-android-compiler:_" const val hilt_navigation_compose = "androidx.hilt:hilt-navigation-compose:1.0.0-alpha03" @@ -157,4 +158,9 @@ object Libs { const val pr_downloader = "com.mindorks.android:prdownloader:_" const val mockito_kotlin = "org.mockito.kotlin:mockito-kotlin:_" + + const val robolectric = "org.robolectric:robolectric:4.4" + + const val junit5_android_test_core = "de.mannodermaus.junit5:android-test-core:_" + const val junit5_android_test_runner = "de.mannodermaus.junit5:android-test-runner:_" } diff --git a/util/build.gradle.kts b/util/build.gradle.kts index e47c848..d4d319e 100644 --- a/util/build.gradle.kts +++ b/util/build.gradle.kts @@ -39,11 +39,12 @@ dependencies { api(platform(Libs.kotlin_coroutine_bom)) api(Libs.kotlin_coroutine_core) + implementation(Libs.kotlin_coroutine_test) api(Libs.mavericks_core) - testImplementation(Libs.junit_jupiter_api) - testImplementation(Libs.junit_jupiter_engine) + implementation(Libs.junit_jupiter_api) + implementation(Libs.junit_jupiter_engine) testImplementation(Libs.mockk_core) diff --git a/versions.properties b/versions.properties index 4685543..cfa350e 100644 --- a/versions.properties +++ b/versions.properties @@ -62,3 +62,5 @@ version.com.airbnb.android..lottie-compose=4.1.0 version.app.cash.turbine..turbine=0.6.1 version.com.mindorks.android..prdownloader=0.6.0 version.org.mockito.kotlin..mockito-kotlin=3.2.0 +version.de.mannodermaus.junit5..android-test-runner=1.2.2 +version.de.mannodermaus.junit5..android-test-core=1.2.2