четверг, 6 декабря 2012 г.

ScreenObject на Robotium

ScreenObject на Robotium

В конце той статьи был приведен пример простого теста. Давайте еще раз взглянем на него.

package com.example.android.notepad.test;

import android.test.ActivityInstrumentationTestCase2;

import com.example.android.notepad.NotesList;
import com.example.android.notepad.R;
import com.jayway.android.robotium.solo.Solo;


public class AddNoteTest extends ActivityInstrumentationTestCase2{
 
 private static final String APP_PACKAGE_NAME = "com.example.android.notepad";
 protected Solo solo;

 @SuppressWarnings("deprecation")
 public AddNoteTest() {
  super(APP_PACKAGE_NAME, NotesList.class);
 }

 public void setUp() throws Exception {
  solo = new Solo(getInstrumentation(), getActivity());
 }
 
 public void testAddNote() throws Exception {
  solo.clickOnActionBarItem(R.id.menu_add);
  //Assert that NoteEditor activity is opened
  solo.assertCurrentActivity("Expected NoteEditor activity", "NoteEditor"); 
 
  //In text field 0, add TestNote
  String note = "TestNote";
  
  solo.enterText(0, note);
  solo.goBack();
  //Assert that TestNote is found
  assertTrue("Note 1 is not found", solo.searchText(note)); 
 }
 
 @Override
 public void tearDown() throws Exception {
  //Robotium will finish all the activities that have been opened
  solo.finishOpenedActivities();
 }
}

Ничего не понятно (или мало что понятно), скажете Вы и будете правы.  Эти тесты выглядят только как вызов API инструмента. Набор функций, которые понимает Robotium, но не тестировщик. Что же стоит делать в таком случае? Как сделать тесты более читабельными, полезными и чтобы в них можно было как можно быстрее разобраться?

Что нам нужно знать для того чтобы писать хорошие тесты? Из web автоматизации большинству из нас известен паттерн PageObject (впервые его опубликовал Martin Fauler,но с немного другим названием WindowDriver).
Существует немало споров как лучше организовать эту модель и стоит ли делать ее вообще. Я поделюсь своим опытом, на основании десятка автоматизированных как веб, так и мобильных проектов.  
Так как мы будем говорить о мобильной разработке,  то слово PageObject уже не подходит, так как у Native приложений не страницы, а экраны. Назовем, этот паттерн, условно, ScreenObject. 
Теперь давайте представим, что экран со списком заметок (рис 1) это Java класс. 
 
Рис. 1
А все функции, которые можно выполнить на этой странице это JavaMethods. Получим, что-то вроде вот этого.


packagecom.jayway.screens;
 
importcom.example.android.notepad.NotesList;
importcom.example.android.notepad.R;
importcom.jayway.android.robotium.solo.Solo;
 
 
public class NotesListScreen extends BaseScreen{
 
 publicNotesListScreen(Solo solo) {
  super(solo, NotesList.class);
 }
  
 public void clickAddNote() {
  //TODO: Add some logic here
 }
  
 publicbooleanisNotePresent(String noteName) {
  //TODO: Add some logic here
  return false;
 }
  
 public void clickNote(String note) {
  //TODO: Add some logic here
 }
  
 public void removeNote(String noteName) {
  //TODO: Add some logic here
 }
}
То есть мы получили класс NotesListScreen с перечнем всех функций на этом экране. Функции получились пустышки, и нам нужно их реализовать. Давайте начнем с функции clickAddNote(). Добавляем Robotium вызов, который нажмет на эту кнопку. Оп, и что произошло? После нажатия на эту кнопку мы попали на совсем другой экран - AddNoteScreen. 
Нам это так же нужно запрограммировать в методе
publicAddNoteScreenclickAddNote() {
 getSolo().clickOnMenuItem(getSolo().getString(R.string.menu_insert));
 returnnewAddNoteScreen(getSolo());
} 
Что получилось, созданный метод будет возвращать объект уже нового экрана, у которого будут уже свои методы по работе только с экраном AddNoteScreen.
Это было ключевое, дальше лишь дело техники.
Как будет выглядеть конечный тест?
packagecom.jayway.test;
 
importandroid.test.suitebuilder.annotation.Smoke;
 
importcom.example.android.notepad.R;
importcom.jayway.android.robotium.solo.Solo;
importcom.jayway.screens.AddNoteScreen;
importcom.jayway.screens.NotesListScreen;
 
 
public class NotePadTest extends BaseTestCase {
 
 private static final String EDITED_TEST = "Edited Test";
 private static final String NOTE_NAME = "Note 1";
  
 @Smoke
 public void testAddNote() throws Exception {
  NotesListScreennoteListScreen = new NotesListScreen(solo);
  assertTrue(noteListScreen.isCurrentActivityOpened());
  AddNoteScreenaddNoteScreen = noteListScreen.clickAddNote();
  addNoteScreen.assertCurrentActivity();
  addNoteScreen.typeNote(NOTE_NAME);
  noteListScreen = addNoteScreen.goBack();
  noteListScreen.assertCurrentActivity();
  assertTrue(NOTE_NAME + " is not found", noteListScreen.isNotePresent(NOTE_NAME));
 }
}
Теперь тест стал намного читабельней, не так ли? Java код начинает выглядеть как обычный тест- кейс, при этом мы видим смену экранов по который "прыгает" пользователь.
Видите как быстро, и не очень сложно мы разобрались с тем как писать правильные тесты на Robotium.
Так же Вы могли заметить, что у меня появился некий базовый класс, от которого унаследован мой тест. Так же у каждого экрана есть унаследованный класс BaseScreen. Эти классы содержат в себе вспомогательные методы, для работы с тестом и экранами.

По прежнему  говорим спасибо Андрею Дзыня.

Комментариев нет:

Отправить комментарий