Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Espressing yourself
Search
Rui Gonçalo
May 30, 2017
Programming
0
66
Espressing yourself
Some hints on how to use dagger and mockito to easily build espresso tests.
Rui Gonçalo
May 30, 2017
Tweet
Share
More Decks by Rui Gonçalo
See All by Rui Gonçalo
NYC Android meetup May 2019
ruigoncalo
0
31
Start speking it @ Droidcon Krakow 2017
ruigoncalo
0
110
Master your custom views
ruigoncalo
1
130
Other Decks in Programming
See All in Programming
レガシーシステムにどう立ち向かうか 複雑さと理想と現実/vs-legacy
suzukihoge
14
2.2k
Outline View in SwiftUI
1024jp
1
330
距離関数を極める! / SESSIONS 2024
gam0022
0
290
Contemporary Test Cases
maaretp
0
140
よくできたテンプレート言語として TypeScript + JSX を利用する試み / Using TypeScript + JSX outside of Web Frontend #TSKaigiKansai
izumin5210
6
1.7k
ローコードSaaSのUXを向上させるためのTypeScript
taro28
1
630
Creating a Free Video Ad Network on the Edge
mizoguchicoji
0
120
macOS でできる リアルタイム動画像処理
biacco42
9
2.4k
イベント駆動で成長して委員会
happymana
1
330
Compose 1.7のTextFieldはPOBox Plusで日本語変換できない
tomoya0x00
0
190
Jakarta EE meets AI
ivargrimstad
0
600
ピラミッド、アイスクリームコーン、SMURF: 自動テストの最適バランスを求めて / Pyramid Ice-Cream-Cone and SMURF
twada
PRO
10
1.3k
Featured
See All Featured
ピンチをチャンスに:未来をつくるプロダクトロードマップ #pmconf2020
aki_iinuma
109
49k
Fashionably flexible responsive web design (full day workshop)
malarkey
405
65k
Done Done
chrislema
181
16k
Adopting Sorbet at Scale
ufuk
73
9.1k
How to Think Like a Performance Engineer
csswizardry
20
1.1k
Refactoring Trust on Your Teams (GOTO; Chicago 2020)
rmw
31
2.7k
A Modern Web Designer's Workflow
chriscoyier
693
190k
How to train your dragon (web standard)
notwaldorf
88
5.7k
Intergalactic Javascript Robots from Outer Space
tanoku
269
27k
Save Time (by Creating Custom Rails Generators)
garrettdimon
PRO
27
840
Visualization
eitanlees
145
15k
The Art of Programming - Codeland 2020
erikaheidi
52
13k
Transcript
espressing yourself @rmgoncalo Rui Gonçalo
Use Espresso to write concise, beautiful, and reliable Android UI
tests
Use Espresso to write concise, beautiful, and reliable Android UI
tests
Use Espresso to write concise, beautiful, and reliable Android UI
tests
MainActivity.kt class MainActivity : AppCompatActivity()
class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) } } MainActivity.kt
class MainActivity : AppCompatActivity() { @Inject lateinit var presenter: MainPresenter
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) } } MainActivity.kt Dagger
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
AppComponent.kt @Singleton @Component(modules = arrayOf(AppModule::class)) interface AppComponent { fun plus(module:
ActivityModule): ActivityComponent fun servicesManager(): ServicesManager } Dagger
AppComponent.kt @Singleton @Component(modules = arrayOf(AppModule::class)) interface AppComponent { fun plus(module:
ActivityModule): ActivityComponent fun servicesManager(): ServicesManager } Dagger AppComp AppModule
ActivityComponent.kt @Subcomponent(modules = arrayOf(ActivityModule::class)) interface ActivityComponent { fun plus(module: MainModule):
MainComponent } Dagger AppComp AppModule ActivityComp ActivityModule
MainComponent.kt @Subcomponent(modules = arrayOf(MainModule::class)) interface MainComponent { fun inject(activity: MainActivity)
} Dagger AppComp AppModule ActivityComp ActivityModule MainComp MainModule
MainModule.kt @Module open class MainModule { open fun provideGetDataUseCase() :
GetDataUseCase { return GetDataUseCase } Dagger AppComp AppModule ActivityComp ActivityModule MainComp MainModule
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
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() { } }
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() } }
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) }
MainActivity.kt class MainActivity : AppCompatActivity(), MainPresenter.View { override fun showResult(result)
{ // update layout } override fun showError(error) // update layout }
MainActivityTest.kt @RunWith(AndroidJUnit4::class) @LargeTest class MainActivityTest { @Rule @JvmField val mainActivityTestRule
= ActivityTestRule<MainActivity>(MainActivity::class.java) @Test fun something() { // test } }
AppComp AppModule ActivityComp ActivityModule MainComp MainModule /src/main/java/com/example/ /src/androidTest/java/com/example/ AppComp AppModuleMock
ActivityComp ActivityModuleMock MainComp MainModuleMock
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
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
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
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
onView(Matcher).perform(ViewAction) onView(Matcher).check(ViewAssertion)
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"))) } }
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
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
Hole19 Android Wear 2.0 app
Hole19 Android Wear 2.0 app
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()) } }
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"))) } }
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() }
None
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
Thank you @rmgoncalo