Skip to content

Commit

Permalink
Change dependency from dexmaker to simple mockito-android
Browse files Browse the repository at this point in the history
Fixed some tests related to FavoritesFragment but still have a non-sdk warning showing up,
this makes the whenThereIsNoDataAndErrorOccursErrorViewStateIsShown() test flaky. Needs fix

#29
  • Loading branch information
JoaquimLey committed Apr 22, 2018
1 parent 18aa2db commit 105f001
Show file tree
Hide file tree
Showing 9 changed files with 68 additions and 34 deletions.
3 changes: 2 additions & 1 deletion transport-eta-android/mobile-ui/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,8 @@ dependencies {
// Android unit tests
kaptAndroidTest deps.dagger.compiler
androidTestImplementation deps.javax.inject
androidTestImplementation deps.dexmaker.linkedin_inline
androidTestImplementation deps.mockito.android
// androidTestImplementation deps.dexmaker.linkedin_inline
// Android Testing Support runner and rules and AAC
androidTestImplementation deps.atsl.rules
androidTestImplementation deps.atsl.runner
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,6 @@ import dagger.android.ContributesAndroidInjector
abstract class TestActivityBindingModule {

@PerActivity // HomeFragmentsBuildersModule::class
@ContributesAndroidInjector(modules = arrayOf(TestFragmentActivityModule::class, TestHomeFragmentsBuildersModule::class))
@ContributesAndroidInjector(modules = arrayOf(TestFragmentActivityModule::class, TestFragmentsBuildersModule::class))
abstract fun bindTestFragmentActivity(): TestFragmentActivity
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.joaquimley.transporteta.ui.di.module

import com.joaquimley.transporteta.presentation.home.favorite.FavoritesViewModelFactory
import com.joaquimley.transporteta.presentation.home.favorite.FavoritesViewModelFactoryImpl
import dagger.Module
import dagger.Provides
import org.mockito.Mockito.mock
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import dagger.Module
import dagger.android.ContributesAndroidInjector

@Module
abstract class TestHomeFragmentsBuildersModule {
abstract class TestFragmentsBuildersModule {

@ContributesAndroidInjector(modules = arrayOf(TestFavoriteFragmentModule::class))
abstract fun contributeFavouritesFragment(): FavoritesFragment
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import android.support.test.espresso.Espresso.onView
import android.support.test.espresso.action.ViewActions.*
import android.support.test.espresso.assertion.ViewAssertions.doesNotExist
import android.support.test.espresso.assertion.ViewAssertions.matches
import android.support.test.espresso.contrib.RecyclerViewActions
import android.support.test.espresso.matcher.ViewMatchers.*
import android.support.test.filters.MediumTest
import android.support.test.rule.ActivityTestRule
Expand All @@ -15,22 +16,26 @@ import com.joaquimley.transporteta.presentation.data.Resource
import com.joaquimley.transporteta.presentation.home.favorite.FavoritesViewModel
import com.joaquimley.transporteta.presentation.model.FavoriteView
import com.joaquimley.transporteta.ui.di.module.TestFavoriteFragmentModule
import com.joaquimley.transporteta.ui.home.favorite.FavoritesAdapter
import com.joaquimley.transporteta.ui.home.favorite.FavoritesFragment
import com.joaquimley.transporteta.ui.test.util.RecyclerViewMatcher
import com.joaquimley.transporteta.ui.testing.TestFragmentActivity
import com.joaquimley.transporteta.ui.testing.factory.TestFactoryFavoriteView
import org.hamcrest.CoreMatchers.not
import org.hamcrest.CoreMatchers.nullValue
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mockito.`when`
import org.mockito.Mockito.mock


@MediumTest
@RunWith(AndroidJUnit4::class)
class FavoritesFragmentTest {

@Rule @JvmField val activityRule = ActivityTestRule(TestFragmentActivity::class.java, true, true)
@Rule @JvmField val activityRule = ActivityTestRule(TestFragmentActivity::class.java, false, true)
@Rule @JvmField val instantTaskExecutorRule = InstantTaskExecutorRule()

private val results = MutableLiveData<Resource<List<FavoriteView>>>()
Expand All @@ -41,11 +46,13 @@ class FavoritesFragmentTest {
@Before
fun setup() {
// Init mock ViewModel
`when`(TestFavoriteFragmentModule.favoritesViewModelsFactory.create()).thenReturn(viewModel)
`when`(TestFavoriteFragmentModule.favoritesViewModelsFactory.create(FavoritesViewModel::class.java)).thenReturn(viewModel)
`when`(viewModel.getFavourites()).thenReturn(results)
// Instantiate fragment and add to the TestFragmentActivity
favoritesFragment = FavoritesFragment.newInstance()
activityRule.activity.addFragment(favoritesFragment)

// Due to Android P non-sdk access we're getting an alert dialog making the tests flaky
}

@Test
Expand All @@ -59,7 +66,8 @@ class FavoritesFragmentTest {
val resultsList = TestFactoryFavoriteView.generateFavoriteViewList()
results.postValue(Resource.success(resultsList))
// Then
onView(withId(R.id.message_view)).check(doesNotExist())
onView(withId(R.id.progress_bar)).check(matches(not(isDisplayed())))
onView(withId(R.id.message_view)).check(matches(not(isDisplayed())))
onView(withId(R.id.recycler_view)).check(matches(isDisplayed()))
}

Expand All @@ -68,7 +76,7 @@ class FavoritesFragmentTest {
// When
results.postValue(Resource.empty())
// Then
onView(withId(R.id.recycler_view)).check(doesNotExist())
onView(withId(R.id.recycler_view)).check(matches(not(isDisplayed())))
onView(withId(R.id.message_view)).check(matches(isDisplayed()))
}

Expand All @@ -81,7 +89,7 @@ class FavoritesFragmentTest {
results.postValue(Resource.error(errorMessage))
// Then
onView(withId(R.id.message_view)).check(matches(isDisplayed()))
onView(withId(R.id.recycler_view)).check(doesNotExist())
onView(withId(R.id.recycler_view)).check(matches(not(isDisplayed())))
}

@Test
Expand All @@ -90,13 +98,16 @@ class FavoritesFragmentTest {
val resultsList = TestFactoryFavoriteView.generateFavoriteViewList()
results.postValue(Resource.success(resultsList))
onView(withId(R.id.recycler_view)).check(matches(isDisplayed()))

// Error occurs
val errorMessage = "Test for error message"
val errorMessage = "Error message for Test"
results.postValue(Resource.error(errorMessage))

// Then
onView(withId(R.id.recycler_view)).check(matches(isDisplayed()))
onView(withId(R.id.message_view)).check(doesNotExist())
// Only snackbar is shown with retry button
onView(withId(R.id.message_view)).check(matches(not(isDisplayed())))

// Snackbar is shown with retry button
onView(withText(errorMessage)).check(matches(isDisplayed()))
onView(withText(R.string.action_retry)).check(matches(isDisplayed()))
}
Expand All @@ -105,14 +116,15 @@ class FavoritesFragmentTest {
fun whenCreateFabIsClickedCreateFavoriteScreenIsShown() {
// When
onView(withId(R.id.fab)).perform(click())
// Check dialog is showing
// Check dialog is showing correctly
onView(withText(R.string.create_favorite_title)).check(matches(isDisplayed()))
// Check
onView(withId(R.id.favorite_code_edit_text)).check(matches(isDisplayed()))
onView(withId(R.id.favorite_title_edit_text)).check(matches(isDisplayed()))
onView(withId(R.id.favorite_code_edit_text)).check(matches(withHint(R.string.create_favorite_code_hint)))
onView(withId(R.id.favorite_title_edit_text)).check(matches(withHint(R.string.create_favorite_title_hint)))

// TODO Fix hints
// onView(withText(R.string.create_favorite_code_hint)).check(matches(isDisplayed()))
// onView(withText(R.string.create_favorite_title_hint)).check(matches(isDisplayed()))
// Dialog Action buttons
onView(withText(R.string.action_create)).check(matches(isDisplayed()))
onView(withText(R.string.action_discard)).check(matches(isDisplayed()))
}
Expand All @@ -125,11 +137,13 @@ class FavoritesFragmentTest {
onView(withText(R.string.action_discard)).perform(click())
// Check is dismissed
onView(withText(R.string.create_favorite_title)).check(doesNotExist())
onView(withText(R.string.action_create)).check(doesNotExist())
onView(withText(R.string.action_discard)).check(doesNotExist())
}

@Test
fun inCreateFavoriteDialogWhenUserClicksCreateWithNoCodeErrorMessageIsShown() {
// Show dialog
// Show error message
onView(withId(R.id.fab)).perform(click())
// Be sure the code field is empty
onView(withId(R.id.favorite_code_edit_text)).perform(clearText())
Expand All @@ -138,8 +152,8 @@ class FavoritesFragmentTest {
// Dialog is not dismissed
onView(withText(R.string.create_favorite_title)).check(matches(isDisplayed()))
// Error message is shown
onView(withText(R.string.error_create_favorite_code_required)).check(matches(isDisplayed()))
// onView(allOf(withParent(R.id.txtPhoneNumber), withText("error text"))).check(matches(isDisplayed()))
val errorMessage = activityRule.activity.getString(R.string.error_create_favorite_code_required)
onView(withId(R.id.favorite_code_edit_text)).check(matches(hasErrorText(errorMessage))).check(matches(isDisplayed()))
}

@Test
Expand All @@ -151,7 +165,7 @@ class FavoritesFragmentTest {
// Start typing
onView(withId(R.id.favorite_code_edit_text)).perform(typeText("1337"))
// Check error message is hidden
onView(withText(R.string.error_create_favorite_code_required)).check(doesNotExist())
onView(withId(R.id.favorite_code_edit_text)).check(matches(hasErrorText(nullValue(String::class.java))))
}


Expand All @@ -160,14 +174,19 @@ class FavoritesFragmentTest {
// When
val resultsList = TestFactoryFavoriteView.generateFavoriteViewList()
results.postValue(Resource.success(resultsList))
// Then
onView(RecyclerViewMatcher.withRecyclerView(R.id.recycler_view).atPosition(0)).check(matches(hasDescendant(withText(resultsList[0].latestEta))))
onView(RecyclerViewMatcher.withRecyclerView(R.id.recycler_view).atPosition(0)).check(matches(hasDescendant(withText(resultsList[0].code.toString()))))
// Assert
onView(withId(R.id.progress_bar)).check(doesNotExist())
// Then check all items
for (favoriteView in resultsList.withIndex()) {
// Scroll to item INDEX
onView(withId(R.id.recycler_view)).perform(RecyclerViewActions.scrollToPosition<FavoritesAdapter.FavoriteViewHolder>(favoriteView.index))
// Check item is displayed correctly
onView(RecyclerViewMatcher.withRecyclerView(R.id.recycler_view).atPosition(favoriteView.index)).check(matches(hasDescendant(withText(resultsList[favoriteView.index].code.toString()))))
onView(RecyclerViewMatcher.withRecyclerView(R.id.recycler_view).atPosition(favoriteView.index)).check(matches(hasDescendant(withText(resultsList[favoriteView.index].latestEta))))
onView(RecyclerViewMatcher.withRecyclerView(R.id.recycler_view).atPosition(favoriteView.index)).check(matches(hasDescendant(withText(resultsList[favoriteView.index].originalText))))
}
}

}


// https://spin.atomicobject.com/2016/04/15/espresso-testing-recyclerviews/
// https://spin.atomicobject.com/2016/04/15/espresso-testing-recyclerviews/
// https://medium.com/@_rpiel/recyclerview-and-espresso-a-complicated-story-3f6f4179652e
Original file line number Diff line number Diff line change
Expand Up @@ -44,4 +44,10 @@ class HomeActivityTest {
// https://www.kotlindevelopment.com/runtime-permissions-espresso-done-right/

// https://developer.android.com/reference/android/support/test/rule/GrantPermissionRule.html

// https://stackoverflow.com/questions/25998659/espresso-how-can-i-check-if-an-activity-is-launched-after-performing-a-certain

// https://github.com/googlesamples/android-testing/tree/master/ui/espresso/IntentsBasicSample

// https://github.com/googlesamples/android-testing/tree/master/ui/espresso/IntentsAdvancedSample
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import kotlinx.android.synthetic.main.fragment_favourites.*
import kotlinx.android.synthetic.main.view_message.*
import javax.inject.Inject


/**
* Created by joaquimley on 24/03/2018.
*/
Expand Down Expand Up @@ -116,15 +117,17 @@ class FavoritesFragment : Fragment() {
message_view.setVisible(false)
if (isLoading) {
if (swipe_refresh.isRefreshing.not() && adapter.isEmpty()) {
progress_bar.visibility = View.VISIBLE
progress_bar?.setVisible(true)
}
} else {
swipe_refresh.isRefreshing = false
progress_bar.visibility = View.GONE
swipe_refresh?.isRefreshing = false
progress_bar?.setVisible(false)
}
}

private fun setupScreenForSuccess(favoriteViewList: List<FavoriteView>) {
swipe_refresh?.isRefreshing = false
progress_bar?.setVisible(false)
message_view?.setVisible(false)
recycler_view?.setVisible(true)
adapter.submitList(favoriteViewList)
Expand All @@ -141,13 +144,13 @@ class FavoritesFragment : Fragment() {
private fun setupScreenForError(message: String?) {
if (adapter.isEmpty()) {
recycler_view?.setVisible(false)
message_view?.setVisible(true)
// TODO set the view to error state
message_text_view?.text = message
message_view?.setVisible(true)
} else {
view?.let {
// TODO -> Add retry button (TDD: still no tests)
Snackbar.make(it, message.toString(), Snackbar.LENGTH_LONG)
message?.let {
Snackbar.make(favorites_fragment_container, it, Snackbar.LENGTH_LONG)
.setAction(R.string.action_retry, { viewModel.retry() })
.show()
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<android.support.design.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/favorites_fragment_container"
android:layout_width="match_parent"
android:layout_height="match_parent">

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@ import com.joaquimley.transporteta.sms.SmsController
abstract class FavoritesViewModelFactory(private val smsController: SmsController) : ViewModelProvider.Factory {

override fun <T : ViewModel?> create(modelClass: Class<T>): T {
return create() as T
if (modelClass is FavoritesViewModel) {
return create() as T
}
throw IllegalStateException("Wrong class type passed ${modelClass.name}")
}

fun create(): FavoritesViewModel {
Expand Down

0 comments on commit 105f001

Please sign in to comment.