Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Recording Meaningful UI Tests

kaskasi
October 14, 2016

Recording Meaningful UI Tests

Espresso Test Recording has been introduced with Android Studio 2.2. Recording tests is as easy as using an app. But how do you assert that your tests are meaningful?

In order to do that you need to consider your use case, the app architecture and the testing strategy.

kaskasi

October 14, 2016
Tweet

More Decks by kaskasi

Other Decks in Technology

Transcript

  1. what I found interesting in tensile tests, is that the

    tests are supposed to fail at some point. And what’s being tested under which parameters the objects don’t behave as expected.
  2. Espresso Test Recording • presented at Google IO 2016 •

    still experimental feature • Available since Android Studio 2.2 Preview 3 • Users can record journeys through the app and perform assertions by interacting with the app on an actual device
  3. Acceptance Criteria given I open the app and I open

    the quiz when I enter answer correctly then digit color green
  4. Acceptance Criteria given I open the app and I open

    the quiz when I enter answer correctly then digit color green given I open the app and I open the quiz when I enter pi incorrectly then button text is Restart
  5. Acceptance Criteria given I open the app and I open

    the quiz when I enter answer correctly then digit color green given I open the app and I open the quiz when I enter pi incorrectly then button text is Restart given I open the app when I scroll thousand digits of pi
  6. Acceptance Criteria • given I open the app and I

    open the quiz • when I enter answer correctly • then digit color green • given I open the app and I open the quiz • when I enter pi incorrectly • then button text is Restart • given I open the app • when I scroll thousand digits of pi
  7. “It is what I sometimes have called the separation of

    concerns, which, even if not perfectly possible, is yet the only available tequnique for effective ordering of one’s thoughts.” Edsger W. Dijkstra, 1974, On the role of schientific thought
  8. Model PiQuiz.java PiQuiz(int position) int position String answer getPosition() setPosition(…)

    getAnswer() setAnswer(…) PiProvider.java String π getDigitOfPi(…) getNumberOfDigitsOfPi()
  9. ViewModel PiQuizViewModel.java CharSequence getAnswer() {}
 void setAnswer(CharSequence answer) {}
 


    boolean isQuestionHowPiStarts() {}
 boolean isButtonTextNext() {}
 boolean isButtonEnabled() {}
 boolean isAnswerColorGreen() {}
 boolean isPossibleToEnterAnswer() {}
 
 String getDigitPosition() {} 
 void onNext() {}
  10. ViewModel PiQuizViewModel.java CharSequence getAnswer() {}
 void setAnswer(CharSequence answer) {}
 


    boolean isQuestionHowPiStarts() {}
 boolean isButtonTextNext() {}
 boolean isButtonEnabled() {}
 boolean isAnswerColorGreen() {}
 boolean isPossibleToEnterAnswer() {}
 
 String getDigitPosition() {} 
 void onNext() {}
  11. UnitTest PiQuizViewModelTest.java @Test
 public void when_correct_answer_ then_answer_color_is_green() {
 PiQuiz quiz

    = new PiQuiz(0);
 PiQuizViewModel viewModel = new PiQuizViewModel(quiz);
 
 viewModel.setAnswer("3");
 assertTrue(viewModel.isAnswerColorGreen()); }
 

  12. UnitTest PiQuizViewModelTest.java @Test
 public void when_wrong_answer_ then_button_text_is_restart() {
 PiQuiz quiz

    = new PiQuiz(0);
 PiQuizViewModel viewModel = new PiQuizViewModel(quiz);
 
 viewModel.setAnswer("4");
 
 assertFalse(viewModel.isButtonTextNext());
 } 
 

  13. PiQuizViewModelTest.java when_answer_is_entered_then_viewmodel_notifies_view when_answer_entered_then_viewmodel_returns_answer then_button_is_not_enabled when_answer_entered_then_button_is_enabled when_correct_answer_entered_then_answer_color_is_green when_wrong_answer_entered_then_answer_color_is_not_green when_correct_answer_entered_then_button_text_is_next when_wrong_answer_entered_then_button_text_is_restart when_position_is_thousand_then_button_text_is_restart

    then_it_is_possible_to_enter_answer when_answer_is_entered_then_it_is_not_possible_to_enter_answer when_answer_is_entered_when_next_is_pressed_then_it_is_possible _to_enter_answer when_next_is_pressed_then_viewmodel_notifies_view_ when_correct_answer_is_entered_when_next_is_pressed _then_quiz_position_is_incremented when_wrong_answer_is_entered_when_restart_is_pressed _then_quiz_position_is_zero when_position_is_thousand_when_correct_answer_is_entered_ when_restart_is_pressed_then_quiz_position_is_zero when_position_is_zero_then_question_is_how_pi_starts then_viewmodel_returns_digit_position_as_text then_viewmodel_returns_pi_quiz
  14. PiQuizViewModelTest.java when_answer_is_entered_then_viewmodel_notifies_view when_answer_entered_then_viewmodel_returns_answer then_button_is_not_enabled when_answer_entered_then_button_is_enabled when_correct_answer_then_answer_color_is_green when_wrong_answer_entered_then_answer_color_is_not_green when_correct_answer_entered_then_button_text_is_next when_wrong_answer_entered_then_button_text_is_restart when_position_is_thousand_then_button_text_is_restart

    then_it_is_possible_to_enter_answer when_answer_is_entered_then_it_is_not_possible_to_enter_answer when_answer_is_entered_when_next_is_pressed_then_it_is_possible _to_enter_answer when_next_is_pressed_then_viewmodel_notifies_view_ when_correct_answer_is_entered_when_next_is_pressed _then_quiz_position_is_incremented when_wrong_answer_is_entered_when_restart_is_pressed _then_quiz_position_is_zero when_position_is_thousand_when_correct_answer_is_entered_ when_restart_is_pressed_then_quiz_position_is_zero when_position_is_zero_then_question_is_how_pi_starts then_viewmodel_returns_digit_position_as_text then_viewmodel_returns_pi_quiz
  15. I don’t like to read Espresso Code ViewInteraction actionMenuItemView =

    onView(
 allOf(withId(R.id.menu_quiz), withContentDescription("Quiz"), isDisplayed()));
 actionMenuItemView.perform(click());
 
 ViewInteraction appCompatEditText = onView(
 allOf(withClassName(is("android.support.v7.widget.A ppCompatEditText")), isDisplayed()));
 appCompatEditText.perform(click());
 
 ViewInteraction appCompatEditText2 = onView(
 allOf(withClassName(is("android.support.v7.widget.A ppCompatEditText")), isDisplayed()));
 appCompatEditText2.perform(replaceText("3"), closeSoftKeyboard());
 
 ViewInteraction appCompatTextView = onView(
 allOf(withId(R.id.quiz_next), withText("Next"), isDisplayed()));

  16. public class OpenQuiz implements Fixture {
 
 @Override
 public void

    perform() {
 ViewInteraction actionMenuItemView = onView(
 allOf( withId(R.id.menu_quiz), withContentDescription(“Quiz"), isDisplayed()));
 actionMenuItemView.perform(click());
 }
 } Open Quiz
  17. public class OpenQuiz implements Fixture {
 
 @Override
 public void

    perform() {
 ViewInteraction actionMenuItemView = onView(
 allOf( withId(R.id.menu_quiz), withContentDescription(“Quiz"), isDisplayed()));
 actionMenuItemView.perform(click());
 }
 } Open Quiz
  18. Enter Answer public class EnterAnswer implements Fixture {
 
 private

    String answer;
 
 public EnterAnswer(String answer) {
 this.answer = answer;
 }
 
 @Override
 public void perform() {
 ViewInteraction appCompatEditText = onView(
 allOf( withClassName( is("android.support.v7.widget.AppCompatEditText")), isDisplayed()));
 appCompatEditText.perform(replaceText(“3”), closeSoftKeyboard());
 }
 }
  19. Enter Answer public class EnterAnswer implements Fixture {
 
 private

    String answer;
 
 public EnterAnswer(String answer) {
 this.answer = answer;
 }
 
 @Override
 public void perform() {
 ViewInteraction appCompatEditText = onView(
 allOf( withClassName( is("android.support.v7.widget.AppCompatEditText")), isDisplayed()));
 appCompatEditText.perform(replaceText(answer), closeSoftKeyboard());
 }
 }
  20. Check Digit Color public class CheckDigitColor implements Assertion {
 


    @ColorRes
 private int color;
 
 public CheckDigitColor(@ColorRes int color) {
 this.color = color;
 }
 
 @Override
 public void performAssertion() {
 ViewInteraction appCompatEditText = onView(
 allOf(withClassName( is(“android.support.v7.widget.AppCompatEditText")), isDisplayed()));
 appCompatEditText.check( matches(withTextColor(R.color.green)));
 }
 }
  21. Check Digit Color public class CheckDigitColor implements Assertion {
 


    @ColorRes
 private int color;
 
 public CheckDigitColor(@ColorRes int color) {
 this.color = color;
 }
 
 @Override
 public void performAssertion() {
 ViewInteraction appCompatEditText = onView(
 allOf(withClassName( is(“android.support.v7.widget.AppCompatEditText")), isDisplayed()));
 appCompatEditText.check( matches(withTextColor(color)));
 }
 }
  22. @Test
 public void Given_in_quiz _when_correct_answer_entered _then_answer_has_green_textcolor() { 
 new OpenQuiz().perform();


    
 new EnterAnswer("3").perform();
 
 new CheckDigitColor(R.color.green) .performAssertion();
 }
  23. @Test
 public void Given_in_quiz _when_wrong_answer_is_entered _then_button_text_is_restart() { 
 new OpenQuiz().perform();


    
 new EnterAnswer("4").perform();
 
 new CheckButtonText(“Restart”) .performAssertion();
 }
  24. PiScrollerTest.java Given_in_scroller_when_scroll_to_1000_digits Given_in_scroller_when_scrolled_to_beginning_then_digits_with_even_position _have_beige_background Given_in_scroller_when_scrolled_to_beginning_then_digits_with_uneven_position _have_white_background PiQuizTest.java Given_open_quiz_when_correct_answer_entered_then_answer_has_green_textcolor Given_open_quiz_when_wrong_answer_entered_then_answer_has_red_textcolor Given_open_quiz_then_button_text_is_next

    Given_open_quiz_when_wrong_answer_is_entered_then_button_text_is_restart Given_open_quiz_when_answer_was_entered_thousand_times_then_button_text _is_restart Given_open_quiz_when_answer_entered_then_next_button_color_is_grey Given_open_quiz_when_answer_entered_then_next_button_is_blue Given_open_quiz_then_question_is_how_does_pi_start Given_open_quiz_when_answer_entered_and_when_next_pressed_then_question _is_the_nth_digit_of_pi Given_open_quiz_then_next_button_is_disabled Given_open_quiz_when_answer_entered_then_next_button_is_enabled
  25. Feature: Quiz
 The app gives direct visual confirmation if quiz

    was answered correctly
 
 Scenario Outline: Input answer
 Given I have a PiScroller
 When I open the Quiz
 When I input answer <answer>
 Then I should <see> text color is green
 
 Examples:
 | answer | see |
 | 3 | true |
 | 4 | false |
  26. @Given("^I have a PiScrollerActivity$")
 public void I_have_a_PiScrollerActivity() {
 assertNotNull(getActivity());
 }


    
 @When("^I open the Quiz$")
 public void I_open_the_quiz() { new OpenQuiz().perform(); }
 
 @When("^I input answer (\\S+)$")
 public void I_input_answer(final String answer) {
 new EnterAnswer(answer).perform();
 }
 
 @Then("^I should (true|false) text color is green$")
 public void I_should_see_textcolor_is_green(final boolean isTextColorGreen) {
 new CheckDigitColor(R.color.green, isTextColorGreen).performAssertion();
 }
  27. given I talk about testing when I am done then

    I say “Thank you” Jan Kettner @realitymatters #devfestHH