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
74
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Espressing yourself
Some hints on how to use dagger and mockito to easily build espresso tests.
Rui Gonçalo
May 30, 2017
More Decks by Rui Gonçalo
See All by Rui Gonçalo
NYC Android meetup May 2019
ruigoncalo
0
38
Start speking it @ Droidcon Krakow 2017
ruigoncalo
0
120
Master your custom views
ruigoncalo
1
150
Other Decks in Programming
See All in Programming
運用ダッシュボードの設計を誰も教えてくれないのだけどみなさんどうしてるんですか? - チームに監視するという文化を根付かせるための第一歩を踏みたい -
satoshi256kbyte
1
110
jsmini JavaScript Engine を作ってみた話
yosuke_furukawa
PRO
0
320
型も通る、synthも通る、それでも危ない 〜AIのCDKの権限とコストを機械で検証する〜 / It Passes Type Checks, It Passes Synth Checks, but It’s Still Risky — Automatically Verifying Permissions and Costs in AI’s CDK —
seike460
PRO
1
550
Laravelで学ぶ Webアプリケーションチューニング入門/web_application_tuning_101
hanhan1978
4
1.8k
実装をデザインガイドラインに追従させるための取り組み / 260731-dip-mosh-design-system
dachi023
0
440
AI時代のPHPer生存戦略 ~「言語、もうなんでもよくない?」に本気で向き合う~
vivion
0
320
the container ship “Apple Silicon”@WWDC26 Recap -Japan-\(region).swift
shingangan
0
120
自動化したのに回らない テスト運用の壁―AI時代の品質責任と生産性
mfunaki
0
160
React本体のコードリーディング
high_g_engineer
1
140
20260722_microCMSで考える、AI時代のコンテンツ運用設計
yosh1
0
390
AWS CDK を「作」ってみた 〜フルスクラッチで見えた CDK の裏側〜 / aws-cdk-from-scratch
gotok365
3
2.8k
人間の目はかわらない、だからJPEGは30年もつ
yuzneri
12
18k
Featured
See All Featured
Are puppies a ranking factor?
jonoalderson
1
3.8k
Odyssey Design
rkendrick25
PRO
2
750
So, you think you're a good person
axbom
PRO
2
2.1k
Paper Plane
katiecoart
PRO
2
53k
Helping Users Find Their Own Way: Creating Modern Search Experiences
danielanewman
31
3.3k
A brief & incomplete history of UX Design for the World Wide Web: 1989–2019
jct
2
460
Visualizing Your Data: Incorporating Mongo into Loggly Infrastructure
mongodb
49
10k
Principles of Awesome APIs and How to Build Them.
keavy
128
18k
Stop Working from a Prison Cell
hatefulcrawdad
274
21k
Thoughts on Productivity
jonyablonski
76
5.3k
GraphQLとの向き合い方2022年版
quramy
50
15k
Building Better People: How to give real-time feedback that sticks.
wjessup
370
20k
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