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
67
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
Six and a half ridiculous things to do with Quarkus
hollycummins
0
170
The Past, Present, and Future of Enterprise Java
ivargrimstad
0
290
Range on Rails ―「多重範囲型」という新たな選択肢が、複雑ロジックを劇的にシンプルにしたワケ
rizap_tech
0
120
Swift Concurrency - 状態監視の罠
objectiveaudio
2
520
Pull-Requestの内容を1クリックで動作確認可能にするワークフロー
natmark
2
500
その面倒な作業、「Dart」にやらせませんか? Flutter開発者のための業務効率化
yordgenome03
1
120
CSC509 Lecture 06
javiergs
PRO
0
260
あなたとKaigi on Rails / Kaigi on Rails + You
shimoju
0
130
Devoxx BE - Local Development in the AI Era
kdubois
0
130
ソフトウェア設計の実践的な考え方
masuda220
PRO
4
580
Web Components で実現する Hotwire とフロントエンドフレームワークの橋渡し / Bridging with Web Components
da1chi
3
2.2k
NixOS + Kubernetesで構築する自宅サーバーのすべて
ichi_h3
0
710
Featured
See All Featured
Understanding Cognitive Biases in Performance Measurement
bluesmoon
30
2.7k
The Illustrated Children's Guide to Kubernetes
chrisshort
49
51k
The Art of Delivering Value - GDevCon NA Keynote
reverentgeek
15
1.7k
Optimizing for Happiness
mojombo
379
70k
Gamification - CAS2011
davidbonilla
81
5.5k
Testing 201, or: Great Expectations
jmmastey
45
7.7k
How to Ace a Technical Interview
jacobian
280
24k
Designing for Performance
lara
610
69k
Responsive Adventures: Dirty Tricks From The Dark Corners of Front-End
smashingmag
252
21k
実際に使うSQLの書き方 徹底解説 / pgcon21j-tutorial
soudai
PRO
189
55k
How GitHub (no longer) Works
holman
315
140k
Sharpening the Axe: The Primacy of Toolmaking
bcantrill
45
2.5k
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