From b734faa574660b005dd5fc9e8510d641d08e1e2e Mon Sep 17 00:00:00 2001 From: Carlos Martinez Date: Thu, 17 Jun 2021 14:20:25 -0400 Subject: [PATCH] Add: shortform fragment test --- core/build.gradle | 9 ++ .../core/extensions/TestingExtensions.kt | 79 +++++++++++++++ shortform/build.gradle | 2 + .../feature/MockShortformRepository.kt | 15 +++ .../feature/ShortformFragmentTest.kt | 96 +++++++++++++++++++ versions.gradle | 12 ++- 6 files changed, 208 insertions(+), 5 deletions(-) create mode 100644 core/src/main/java/dev/carlos/core/extensions/TestingExtensions.kt create mode 100644 shortform/src/androidTest/java/dev/carlos/shortform/feature/MockShortformRepository.kt create mode 100644 shortform/src/androidTest/java/dev/carlos/shortform/feature/ShortformFragmentTest.kt diff --git a/core/build.gradle b/core/build.gradle index f47fd63..ef0cde5 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -29,5 +29,14 @@ dependencies { api deps.core.rx.android api deps.core.thirdparty.timber + api deps.testing.junit + api deps.testing.koin + api deps.testing.core + api deps.testing.rules + api deps.testing.runner + api deps.testing.ext + api deps.testing.espresso + api deps.testing.fragments + kapt deps.core.room.compiler } diff --git a/core/src/main/java/dev/carlos/core/extensions/TestingExtensions.kt b/core/src/main/java/dev/carlos/core/extensions/TestingExtensions.kt new file mode 100644 index 0000000..00c6574 --- /dev/null +++ b/core/src/main/java/dev/carlos/core/extensions/TestingExtensions.kt @@ -0,0 +1,79 @@ +package dev.carlos.core.extensions + +import android.view.KeyEvent +import androidx.annotation.IdRes +import androidx.annotation.RestrictTo +import androidx.test.espresso.Espresso +import androidx.test.espresso.ViewInteraction +import androidx.test.espresso.action.ViewActions +import androidx.test.espresso.action.ViewActions.closeSoftKeyboard +import androidx.test.espresso.action.ViewActions.typeText +import androidx.test.espresso.assertion.ViewAssertions +import androidx.test.espresso.matcher.ViewMatchers +import androidx.test.espresso.matcher.ViewMatchers.withText +import org.hamcrest.Matchers +import org.hamcrest.Matchers.allOf +import org.junit.Assert + +@RestrictTo(RestrictTo.Scope.TESTS) +fun String.isTextDisplayed() = Espresso.onView(withText(this)).check(ViewAssertions.matches(ViewMatchers.isDisplayed())) + +@RestrictTo(RestrictTo.Scope.TESTS) +fun Int.isDisplayed(): ViewInteraction = Espresso.onView(ViewMatchers.withId(this)) + .check(ViewAssertions.matches(ViewMatchers.isDisplayed())) + +@RestrictTo(RestrictTo.Scope.TESTS) +fun Int.isNotDisplayed(): ViewInteraction = Espresso.onView(ViewMatchers.withId(this)) + .check(ViewAssertions.matches(Matchers.not(ViewMatchers.isDisplayed()))) + +@RestrictTo(RestrictTo.Scope.TESTS) +fun Int.click(): ViewInteraction = Espresso.onView(ViewMatchers.withId(this)) + .check(ViewAssertions.matches(ViewMatchers.isDisplayed())) + .perform(ViewActions.click()) + +@RestrictTo(RestrictTo.Scope.TESTS) +fun Int.clickOnClickWithId(@IdRes childId: Int): ViewInteraction = Espresso.onView( + allOf( + ViewMatchers.withId(childId), + ViewMatchers.withParent(ViewMatchers.withId(this)) + ) +) + .check(ViewAssertions.matches(ViewMatchers.isDisplayed())) + .perform(ViewActions.click()) + +@RestrictTo(RestrictTo.Scope.TESTS) +fun Int.clickOnClickWithText(text: String): ViewInteraction = Espresso.onView( + allOf( + withText(text), + ViewMatchers.withParent(ViewMatchers.withId(this)) + ) +) + .check(ViewAssertions.matches(ViewMatchers.isDisplayed())) + .perform(ViewActions.click()) + +@RestrictTo(RestrictTo.Scope.TESTS) +fun Int.typeOn(text: String): ViewInteraction = Espresso.onView(ViewMatchers.withId(this)).perform(typeText(text), closeSoftKeyboard()) + +@RestrictTo(RestrictTo.Scope.TESTS) +fun Int.pressEnterKey(): ViewInteraction = Espresso.onView(ViewMatchers.withId(this)) + .perform(ViewActions.pressKey(KeyEvent.KEYCODE_ENTER)) + +@RestrictTo(RestrictTo.Scope.TESTS) +fun String.isDisplayed(): ViewInteraction = Espresso.onView(ViewMatchers.withSubstring(this)) + .check(ViewAssertions.matches(ViewMatchers.isDisplayed())) + +@RestrictTo(RestrictTo.Scope.TESTS) +fun String.isHinted(): ViewInteraction = Espresso.onView(ViewMatchers.withHint(this)) + .check(ViewAssertions.matches(ViewMatchers.isDisplayed())) + +@RestrictTo(RestrictTo.Scope.TESTS) +fun String.isNotDisplayed(): ViewInteraction = Espresso.onView(withText(this)) + .check(ViewAssertions.matches(Matchers.not(ViewMatchers.isDisplayed()))) + +@RestrictTo(RestrictTo.Scope.TESTS) +fun String.click(): ViewInteraction = Espresso.onView(withText(this)) + .check(ViewAssertions.matches(ViewMatchers.isDisplayed())) + .perform(ViewActions.click()) + +@RestrictTo(RestrictTo.Scope.TESTS) +fun T.isEquals(actual: T) = Assert.assertEquals(this, actual) diff --git a/shortform/build.gradle b/shortform/build.gradle index 92d439c..11c2a72 100644 --- a/shortform/build.gradle +++ b/shortform/build.gradle @@ -13,4 +13,6 @@ android { dependencies { implementation project(':core') + testImplementation project(':core') + androidTestImplementation project(':core') } diff --git a/shortform/src/androidTest/java/dev/carlos/shortform/feature/MockShortformRepository.kt b/shortform/src/androidTest/java/dev/carlos/shortform/feature/MockShortformRepository.kt new file mode 100644 index 0000000..304f011 --- /dev/null +++ b/shortform/src/androidTest/java/dev/carlos/shortform/feature/MockShortformRepository.kt @@ -0,0 +1,15 @@ +package dev.carlos.shortform.feature + +import dev.carlos.shortform.data.models.ShortformModel +import dev.carlos.shortform.domain.ShortformRepository +import io.reactivex.Single + +class MockShortformRepository( + private val searchedAcronym: String, + private val response: List +) : + ShortformRepository { + override fun getShortformDefinition(acronym: String): Single { + return Single.fromCallable { ShortformModel(searchedAcronym, response) } + } +} diff --git a/shortform/src/androidTest/java/dev/carlos/shortform/feature/ShortformFragmentTest.kt b/shortform/src/androidTest/java/dev/carlos/shortform/feature/ShortformFragmentTest.kt new file mode 100644 index 0000000..286525b --- /dev/null +++ b/shortform/src/androidTest/java/dev/carlos/shortform/feature/ShortformFragmentTest.kt @@ -0,0 +1,96 @@ +package dev.carlos.shortform.feature + +import androidx.fragment.app.testing.launchFragmentInContainer +import androidx.test.platform.app.InstrumentationRegistry +import dev.carlos.core.extensions.isTextDisplayed +import dev.carlos.core.extensions.pressEnterKey +import dev.carlos.core.extensions.typeOn +import dev.carlos.core.scheduler.Scheduler +import dev.carlos.core.scheduler.SchedulerProvider +import dev.carlos.shortform.R +import dev.carlos.shortform.data.models.ShortformModel +import dev.carlos.shortform.domain.GetShortformDefinition +import dev.carlos.shortform.domain.ShortformRepository +import dev.carlos.shortform.viewmodels.ShortformViewmodel +import org.junit.After +import org.junit.Before +import org.junit.Test +import org.koin.androidx.viewmodel.dsl.viewModel +import org.koin.core.context.loadKoinModules +import org.koin.core.context.startKoin +import org.koin.core.context.stopKoin +import org.koin.dsl.module +import java.lang.Thread.sleep + +class ShortformFragmentTest { + + @Before + fun setupKoin() { + startKoin { + InstrumentationRegistry.getInstrumentation().targetContext + modules(module { + factory { GetShortformDefinition(get(), get()) } + single { SchedulerProvider() } + viewModel { ShortformViewmodel(get()) } + }) + } + } + + @After + fun killKoin() { + stopKoin() + } + + @Test + fun shouldShowLongforms_whenSearchingForValidAcronym() { + acronyms { + searchValidAcronym() + } should { + showLongforms() + } + } + + private fun acronyms(func: AcronymsRobot.() -> Unit) = + AcronymsRobot().apply { + func() + } +} + +class AcronymsRobot { + + fun searchValidAcronym() { + loadKoinModules( + module { + factory { MockShortformRepository("Valid", loadTwoLongforms()) } + } + ) + launchFragmentInContainer() + R.id.shortform_definition_search_field.typeOn("Valid") + R.id.shortform_definition_search_field.pressEnterKey() + } + + infix fun should(func: AcronymsResult.() -> Unit) { + AcronymsResult().apply { func() } + } + + private fun loadTwoLongforms() = listOf( + ShortformModel.LongformModel( + "Valid 1", + 1, + 101 + ), + ShortformModel.LongformModel( + "Valid 2", + 2, + 102 + ) + ) +} + +class AcronymsResult { + fun showLongforms() { + sleep(200) + "Valid 1".isTextDisplayed() + "Valid 2".isTextDisplayed() + } +} diff --git a/versions.gradle b/versions.gradle index ed5da03..b7ecb4e 100644 --- a/versions.gradle +++ b/versions.gradle @@ -18,10 +18,11 @@ versions.timber = "4.7.1" versions.koin = "2.2.3" versions.rx_core = "2.2.21" versions.rx_android = "2.1.1" -versions.junit = "4.13.2" -versions.test = "1.3.0" -versions.test_ext = "1.1.2" -versions.espresso = "3.3.0" +versions.junit = "4.13" +versions.test = "1.2.0" +versions.test_ext = "1.1.1" +versions.espresso = "3.2.0" +versions.fragments = "1.2.0" def build_versions = [:] build_versions.min_sdk = 21 @@ -105,8 +106,9 @@ testing.core = "androidx.test:core:$versions.test" testing.rules = "androidx.test:rules:$versions.test" testing.runner = "androidx.test:runner:$versions.test" testing.ext = "androidx.test.ext:junit:$versions.test_ext" -testing.koin = "org.koin:koin-test:$versions.koin" +testing.koin = "io.insert-koin:koin-test:$versions.koin" testing.espresso = "androidx.test.espresso:espresso-core:$versions.espresso" +testing.fragments = "androidx.fragment:fragment-testing:$versions.fragments" deps.testing = testing ext.deps = deps