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
Sponsored
·
Your Podcast. Everywhere. Effortlessly.
Share. Educate. Inspire. Entertain. You do you. We'll handle the rest.
→
Rui Gonçalo
May 30, 2017
Programming
0
69
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
34
Start speking it @ Droidcon Krakow 2017
ruigoncalo
0
120
Master your custom views
ruigoncalo
1
140
Other Decks in Programming
See All in Programming
エンジニアの「手元の自動化」を加速するn8n 2026.02.27
symy2co
0
150
ポーリング処理廃止によるイベント駆動アーキテクチャへの移行
seitarof
3
1.1k
Claude Code Skill入門
mayahoney
0
360
Claude Codeセッション現状確認 2026福岡 / fukuoka-aicoding-00-beacon
monochromegane
4
420
「抽象に依存せよ」が分からなかった新卒1年目の私が Goのインターフェースと和解するまで
kurogenki
0
110
AI駆動開発の本音 〜Claude Code並列開発で見えたエンジニアの新しい役割〜
hisuzuya
4
500
TipKitTips
ktcryomm
0
170
モダンOBSプラグイン開発
umireon
0
110
社内規程RAGの精度を73.3% → 100%に改善した話
oharu121
13
8k
ふつうのRubyist、ちいさなデバイス、大きな一年 / Ordinary Rubyists, Tiny Devices, Big Year
chobishiba
1
440
Takumiから考えるSecurity_Maturity_Model.pdf
gessy0129
1
140
nilとは何か 〜interfaceの構造とnil!=nilから理解する〜
kuro_kurorrr
3
1.9k
Featured
See All Featured
The Illustrated Children's Guide to Kubernetes
chrisshort
51
52k
Git: the NoSQL Database
bkeepers
PRO
432
66k
Abbi's Birthday
coloredviolet
2
5.3k
Exploring anti-patterns in Rails
aemeredith
2
290
Ten Tips & Tricks for a 🌱 transition
stuffmc
0
87
The State of eCommerce SEO: How to Win in Today's Products SERPs - #SEOweek
aleyda
2
9.9k
Leo the Paperboy
mayatellez
4
1.5k
Design of three-dimensional binary manipulators for pick-and-place task avoiding obstacles (IECON2024)
konakalab
0
380
Unlocking the hidden potential of vector embeddings in international SEO
frankvandijk
0
200
The Invisible Side of Design
smashingmag
302
51k
Sam Torres - BigQuery for SEOs
techseoconnect
PRO
0
220
Distributed Sagas: A Protocol for Coordinating Microservices
caitiem20
333
22k
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