Slide 1

Slide 1 text

No content

Slide 2

Slide 2 text

ROBOTS ESPRESSO AND

Slide 3

Slide 3 text

ESPRESSO

Slide 4

Slide 4 text

VIEWINTERACTION interface ViewInteraction { fun check(viewAssertion: ViewAssertion): ViewInteraction fun perform(vararg viewActions: ViewAction): ViewInteraction fun inRoot(rootMatcher: Matcher): ViewInteraction fun noActivity(): ViewInteraction fun withFailureHandler(failureHandler: FailureHandler): ViewInteraction }

Slide 5

Slide 5 text

VIEWINTERACTION interface ViewInteraction { fun check(viewAssertion: ViewAssertion): ViewInteraction fun perform(vararg viewActions: ViewAction): ViewInteraction fun inRoot(rootMatcher: Matcher): ViewInteraction fun noActivity(): ViewInteraction fun withFailureHandler(failureHandler: FailureHandler): ViewInteraction }

Slide 6

Slide 6 text

VIEWINTERACTION interface ViewInteraction { fun check(viewAssertion: ViewAssertion): ViewInteraction fun perform(vararg viewActions: ViewAction): ViewInteraction fun inRoot(rootMatcher: Matcher): ViewInteraction fun noActivity(): ViewInteraction fun withFailureHandler(failureHandler: FailureHandler): ViewInteraction }

Slide 7

Slide 7 text

VIEWINTERACTION @Test fun myTest() { val interaction: ViewInteraction = Espresso.onView(myView) }

Slide 8

Slide 8 text

VIEWINTERACTION @Test fun myTest() { val interaction: ViewInteraction = Espresso.onView(myView) .check(…) }

Slide 9

Slide 9 text

VIEWINTERACTION @Test fun myTest() { val interaction: ViewInteraction = Espresso.onView(myView) .check(…) .perform(…) .check(…) }

Slide 10

Slide 10 text

TWO MOVES OF ESPRESSO ▸ ViewActions ▸ perform(), type(), click()

Slide 11

Slide 11 text

TWO MOVES OF ESPRESSO ▸ ViewActions ▸ perform(), type(), click() ▸ ViewAssertions ▸ isDisplayed(), isSelected(), isEnabled()

Slide 12

Slide 12 text

TWO MOVES OF ESPRESSO @Test fun emailField_displaysWhatIsTyped() { Espresso.onView(withId(R.id.email)) .check(isDisplayed()) .perform(typeText(“[email protected]")) .check(matches(withText("[email protected]"))) }

Slide 13

Slide 13 text

VIEW ASSERTIONS @Test fun emailField_displaysWhatIsTyped() { Espresso.onView(withId(R.id.email)) .check(isDisplayed()) .perform(typeText(“person@email")) .check(matches(withText("[email protected]"))) }

Slide 14

Slide 14 text

VIEW ACTIONS @Test fun emailField_displaysWhatIsTyped() { Espresso.onView(withId(R.id.email)) .check(isDisplayed()) .perform(typeText(“[email protected]")) .check(matches(withText("[email protected]"))) }

Slide 15

Slide 15 text

ESPRESSO IS BITTER

Slide 16

Slide 16 text

ESPRESSO NEEDS SUGAR

Slide 17

Slide 17 text

ESPRESSO NEEDS INFIX

Slide 18

Slide 18 text

ESPRESSO NEEDS INFIX

Slide 19

Slide 19 text

EspressoTest.kt interface EspressoTest { val click: ViewAction get() = ViewActions.click() val visible: ViewMatcher get() = ViewMatchers.isDisplayed() infix fun type(text: String): ViewAction = ViewActions.typeText(text) infix fun Int.shouldBe(viewMatcher: ViewMatcher): ViewInteraction = Espresso.onView(ViewMatchers.withId(this)) .check(ViewAssertions.matches(viewMatcher)) infix fun Int.shouldHaveText(text: String): ViewInteraction = Espresso.onView(ViewMatchers.withId(this)) .check(ViewAssertions.matches(withText(text))) }

Slide 20

Slide 20 text

PRE-INFIX @Test fun emailField_displaysWhatIsTyped() { Espresso.onView(withId(R.id.email)) .check(isDisplayed()) .perform(typeText(“[email protected]")) .check(matches(withText("[email protected]"))) }

Slide 21

Slide 21 text

@Test fun emailField_displaysWhatIsTyped() { R.id.email shouldBe displayed click on R.id.email type("[email protected]") in R.id.email R.id.email shouldHaveText “[email protected]" } INFIX

Slide 22

Slide 22 text

@Test fun emailField_displaysWhatIsTyped() { R.id.email shouldBe displayed click on R.id.email type("[email protected]") in R.id.email R.id.email shouldHaveText “[email protected]" } INFIX

Slide 23

Slide 23 text

@Test fun emailField_displaysWhatIsTyped() { click on R.id.email type("[email protected]") in R.id.email R.id.email shouldHaveText “person@email" } INFIX

Slide 24

Slide 24 text

ROBOTS

Slide 25

Slide 25 text

MODEL VIEWMODEL VIEW APPLICATION ARCHITECTURE

Slide 26

Slide 26 text

MODEL VIEWMODEL VIEW TEST ARCHITECTURE TESTS + VIEW ACCESS

Slide 27

Slide 27 text

MODEL VIEWMODEL VIEW TESTS TEST ARCHITECTURE VIEW ACCESS

Slide 28

Slide 28 text

Robot.kt abstract class Robot { @get:LayoutRes protected abstract val layout: Int fun setFailureHandler(context: Context) { Espresso.setFailureHandler { error, viewMatcher !-> takeScreenshot("test_failed") DefaultFailureHandler(context).handle(error, viewMatcher) } } fun takeScreenshot(description: String) { Timber.v("click click! "-- $description") } }

Slide 29

Slide 29 text

abstract class Robot { @get:LayoutRes protected abstract val layout: Int fun setFailureHandler(context: Context) { Espresso.setFailureHandler { error, viewMatcher !-> takeScreenshot("test_failed") DefaultFailureHandler(context).handle(error, viewMatcher) } } fun takeScreenshot(description: String) { Timber.v("click click! "-- $description") } } Robot.kt

Slide 30

Slide 30 text

abstract class Robot { @get:LayoutRes protected abstract val layout: Int fun setFailureHandler(context: Context) { Espresso.setFailureHandler { error, viewMatcher !-> takeScreenshot("test_failed") DefaultFailureHandler(context).handle(error, viewMatcher) } } fun takeScreenshot(description: String) { Timber.v("click click! "-- $description") } } Robot.kt

Slide 31

Slide 31 text

abstract class Robot { @get:LayoutRes protected abstract val layout: Int fun setFailureHandler(context: Context) { Espresso.setFailureHandler { error, viewMatcher !-> takeScreenshot("test_failed") DefaultFailureHandler(context).handle(error, viewMatcher) } } fun takeScreenshot(description: String) { Timber.v("click click! "-- $description") } } Robot.kt

Slide 32

Slide 32 text

LogInRobot.kt class LogInRobot : Robot(), EspressoTest { override val layout: Int = R.layout.activity_login object Ids { const val USERNAME = R.id.etUsername const val PASSWORD = R.id.etPassword const val SHOW_PASSWORD = R.id.btnShowPassword const val SIGN_IN = R.id.btnSignIn const val EULA = R.id.btnEula } … }

Slide 33

Slide 33 text

LogInRobot.kt class LogInRobot : Robot(), EspressoTest { fun typeUsername(userName: String = USERNAME) { click on Ids.USERNAME type(userName) on Ids.USERNAME Espresso.closeSoftKeyboard() takeScreenshot("type username $userName") } fun verifyUserName(userName: String) { Ids.USERNAME shouldHaveText userName takeScreenshot(“compare username $userName") } }

Slide 34

Slide 34 text

LogInRobot.kt fun EspressoTest.logIn(func: LogInRobot.() "-> Unit): LogInRobot = LogInRobot().apply { func() }

Slide 35

Slide 35 text

LogInActivityTest.kt fun EspressoTest.logIn(func: LogInRobot.() "-> Unit): LogInRobot = LogInRobot().apply { func() } @Test fun emailField_displaysWhatIsTyped() { logIn { typeUsername("[email protected]") verifyUserName("[email protected]") } }

Slide 36

Slide 36 text

LogInActivityTest.kt @Test fun demoThings() = runBlocking { landing { "//""... } logIn { typeUsername("[email protected]") typePassword("Start123") verifyUsername("[email protected]") clickSignIn() } }