Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Espressing yourself

Espressing yourself

Some hints on how to use dagger and mockito to easily build espresso tests.

Rui Gonçalo

May 30, 2017
Tweet

More Decks by Rui Gonçalo

Other Decks in Programming

Transcript

  1. class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) {

    super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) } } MainActivity.kt
  2. class MainActivity : AppCompatActivity() { @Inject lateinit var presenter: MainPresenter

    override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) } } MainActivity.kt Dagger
  3. MainPresenter.kt class MainPresenter @Inject constructor( private val servicesManager: ServicesManager, private

    val getDataUseCase: GetDataUseCase) { private lateinit var view: MainPresenter.View fun attachView(view: MainPresenter.View) { this.view = view } ... interface View { ... } } Dagger
  4. AppComponent.kt @Singleton @Component(modules = arrayOf(AppModule::class)) interface AppComponent { fun plus(module:

    ActivityModule): ActivityComponent fun servicesManager(): ServicesManager } Dagger
  5. AppComponent.kt @Singleton @Component(modules = arrayOf(AppModule::class)) interface AppComponent { fun plus(module:

    ActivityModule): ActivityComponent fun servicesManager(): ServicesManager } Dagger AppComp AppModule
  6. MainModule.kt @Module open class MainModule { open fun provideGetDataUseCase() :

    GetDataUseCase { return GetDataUseCase } Dagger AppComp AppModule ActivityComp ActivityModule MainComp MainModule
  7. Dagger AppComp AppModule ActivityComp ActivityModule MainComp MainModule class MainActivity :

    AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) (application as App) .appComponent .plus(ActivityModule(this)) .plus(MainModule()) .inject(this) } } MainActivity.kt
  8. MainPresenter.kt class MainPresenter @Inject constructor( private val servicesManager: ServicesManager, private

    val getDataUseCase: GetDataUseCase) { fun attachView(view: MainPresenter.View) { this.view = view } fun start() { } fun stop() { } }
  9. MainPresenter.kt class MainPresenter (getDataUseCase) { private val subscriptions by lazy

    { CompositeSubscription() } fun start() { subscriptions.add( getDataUseCase.build() .subscribeOn(...) .observeOn(AndroidSchedulers.mainThread()) .subscribe( {result -> view.showResult(result)} , {error -> view.showError(error)}) ) } fun stop() { subscriptions.clear() } }
  10. MainActivity.kt class MainActivity : AppCompatActivity(), MainPresenter.View { @Inject lateinit var

    presenter: MainPresenter override fun onStart(){ super.onStart() presenter.start() } override fun onStop(){ super.onStop() presenter.stop() } override fun showResult(result) override fun showError(error) }
  11. MainActivityTest.kt @RunWith(AndroidJUnit4::class) @LargeTest class MainActivityTest { @Rule @JvmField val mainActivityTestRule

    = ActivityTestRule<MainActivity>(MainActivity::class.java) @Test fun something() { // test } }
  12. MainActivityTest.kt @RunWith(AndroidJUnit4::class) @LargeTest class MainActivityTest { @Rule @JvmField val mainActivityTestRule

    = ActivityTestRule<MainActivity>(MainActivity::class.java) @Test fun something() { // test } } https://github.com/fabioCollini/DaggerMock
  13. MainActivityTest.kt @RunWith(AndroidJUnit4::class) @LargeTest class MainActivityTest { val app = InstrumentationRegistry.getInstrumentation()

    .targetContext .applicationContext as App @Rule @JvmField val appComponentRule = DaggerMockRule(AppComponent::class.java, AppModule(app)). set { component -> app.appComponent = component } @Mock lateinit var getDataUseCase: GetDataUseCase @Mock lateinit var servicesManager: ServicesManager } https://github.com/fabioCollini/DaggerMock
  14. MainActivityTest.kt @RunWith(AndroidJUnit4::class) @LargeTest class MainActivityTest { @Mock lateinit var getDataUseCase:

    GetDataUseCase @Test fun something() { `when`(getDataUseCase.build()).thenReturn(Observable.just(result)) // test } } https://github.com/fabioCollini/DaggerMock
  15. MainActivityTest.kt @RunWith(AndroidJUnit4::class) @LargeTest class MainActivityTest { @Rule @JvmField val mainActivityTestRule

    = ActivityTestRule<MainActivity>(MainActivity::class.java, false, false) @Test fun something() { `when`(getDataUseCase.build()).thenReturn(Observable.just(result)) mainActivityTestRule.launchActivity() // test } } launchActivity
  16. MainActivityTest.kt @RunWith(AndroidJUnit4::class) @LargeTest class MainActivityTest { @Test fun something() {

    `when`(getDataUseCase.build()).thenReturn(Observable.just(result)) mainActivityTestRule.launchActivity() onView(withId(R.id.text)).check(matches(withText("result"))) } }
  17. MainActivityTest.kt @RunWith(AndroidJUnit4::class) @LargeTest class MainActivityTest { @Test fun something() {

    `when`(getDataUseCase.build()).thenReturn(Observable.just(result)) mainActivityTestRule.launchActivity() onView(withId(R.id.text)).check(matches(withText("result"))) } } http://jakewharton.com/testing-robots
  18. MainActivityTest.kt @RunWith(AndroidJUnit4::class) @LargeTest class MainActivityTest { val mainActions = MainActivityActions()

    val mainAssertions = MainActivityAssertions() @Test fun something() { `when`(getDataUseCase.build()).thenReturn(Observable.just(result)) mainActivityTestRule.launchActivity() mainAssertions.isDisplayingResult() } } http://jakewharton.com/testing-robots
  19. RoundActions.kt class RoundActions { fun onRound(func: RoundActions.() -> Unit) =

    RoundActions().apply { func() } fun openDrawer() { onView(withId(R.id.peekView)).perform(click()) } fun selectDistanceUnit(unit: DistanceUnit) { if (unit == DistanceUnit.METRIC) { onView(withId(R.id.metric)).perform(click()) } else { onView(withId(R.id.imperial)).perform(click()) } }
  20. RoundAssertions.kt class RoundAssertions { fun isDrawerOpen() { onView(withId(R.id.drawerContent)).check(matches(isCompletelyDisplayed())) } fun

    isDisplayingMetricLabel() { onView(allOf(withId(R.id.distanceUnitLabel), isCompletelyDisplayed())) .check(matches(withText("m"))) } }
  21. RoundActivityTest.kt class RoundActivityTest { @Test fun changeDistanceUnitsToMetric() { `when`(getDistanceUnitsUseCase.build()) .thenReturn(Observable.just(DistanceUnit.IMPERIAL))

    roundActivityTestRule.launchActivity() roundActions.onRound { openDrawer() openDistanceUnits() selectDistanceUnit(DistanceUnit.METRIC) } roundAssertions.isDisplayingMetricLabel() }
  22. Automatic UI testing spares manual QA tasks Make sure *nothing*

    breaks on refactoring Test on a set of emulators/real devices Test on different locales