Что пишут в блогах

Подписаться

Онлайн-тренинги

Что пишут в блогах (EN)

Разделы портала

Про инструменты

.
Надежные тесты для автоматизации тестирования Android приложений с Robotium
18.05.2012 11:11

Автор: Андрей Дзыня

Не так давно я закончил первую статью из цикла автоматизации мобильных приложений. Я попытался максимально полно дать информацию по установке требуемого окружения, для разработки и автоматизации тестирования NativeAndroid приложений, при помощи инструмента Robotium.

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


01 package com.example.android.notepad.test;
02    
03    import android.test.ActivityInstrumentationTestCase2;
04    
05    import com.example.android.notepad.NotesList;
06    import com.jayway.android.robotium.solo.Solo;
07    
08    /**
09     * Add note test
10     * Example of simple Robotium test
11     *
12     * @author adzynia
13     *
14     */
15    public class AddNoteTest extends ActivityInstrumentationTestCase2<NotesList>{
16        
17        private static final String APP_PACKAGE_NAME = "com.example.android.notepad";
18        protected Solo solo;
19    
20        public AddNoteTest() {
21            super(APP_PACKAGE_NAME, NotesList.class);
22        }
23    
24        public void setUp() throws Exception {
25            solo = new Solo(getInstrumentation(), getActivity());
26        }
27        
28        public void testAddNote() throws Exception {
29            solo.clickOnMenuItem("Add note");
30            //Assert that NoteEditor activity is opened
31            solo.assertCurrentActivity("Expected NoteEditor activity", "NoteEditor");
32            //In text field 0, add TestNote
33            String note = "TestNote";
34            solo.enterText(0, note);
35            solo.goBack();
36            //Assert that TestNote is found
37            assertTrue("Note 1 is not found", solo.searchText(note));
38        }
39        
40        @Override
41        public void tearDown() throws Exception {
42            //Robotium will finish all the activities that have been opened
43            solo.finishOpenedActivities();
44        }
45    }

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

Давайте начнем с небольшой теории. Для тех, кто уже успешно занимался web автоматизацией, текст ниже можно не читать.

Существует некий подход по именованию классов и функций, который получил название DSL (DomainSpecificLanguage). В чем суть этого подхода?

Wikipedia

Языки программирования предметной области, дополненные технологиями метапрограммирования, являются эффективным средством автоматизации разработки программного обеспечения и в настоящий момент находят широкое применение в области информационных технологий.

Процесс создания нового предметно-ориентированного языка состоит из трех шагов:

  1. Определение абстрактного синтаксиса.
  2. Определение конкретного синтаксиса.
  3. Определение правил трансформации.

Для тех, кто не понял: DSL это описание классов и функций в зависимости от предметного домена приложения, которое Вы разрабатываете. Например:

  • DSL для подсчета зарплат.
  • DSL для оплаты счета.
  • DSL для продажи мультимедийного контента.

Каждая из отраслей (доменов) содержит в себе функции с разным именованием, хотя, иногда, могут выполнять одну и ту же функциональность.

Надеюсь с этим понятно.

Что еще нам нужно знать для того чтобы писать хорошие тесты? Из web автоматизации большинству из нас известен паттерн PageObject (впервые его опубликовал Martin Fauler,но с немного другим названием WindowDriver).

Существует немало споров как лучше организовать эту модель и стоит ли делать ее вообще. Я поделюсь своим опытом, на основании десятка автоматизированных как веб, так и мобильных проектов.

Так как мы будем говорить о мобильной разработке, то слово PageObject уже не подходит, так как у Native приложений не страницы, а экраны. Назовем, этот паттерн, условно, ScreenObject.

Теперь давайте представим, что экран со списком заметок (рис 1) это Java класс.

Рис. 1

А все функции, которые можно выполнить на этой странице это JavaMethods. Получим, что-то вроде вот этого.

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

public class NotesListScreen extends BaseScreen<NotesList> {
	public NotesListScreen(Solo solo) {
super(solo, NotesList.class);
}
public void clickAddNote() {
//TODO: Add some logic here
}
public booleanisNotePresent(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.

Нам это так же нужно запрограммировать в методе

public AddNoteScreen click AddNote() {
getSolo().clickOnMenuItem(getSolo().getString(R.string.menu_insert));
return newAddNoteScreen(getSolo());
}

Что получилось, созданный метод будет возвращать объект уже нового экрана, у которого будут уже свои методы по работе только с экраном AddNoteScreen.

Это было ключевое, дальше лишь дело техники.

Как будет выглядеть конечный тест?

package com.jayway.test;
import android.test.suitebuilder.annotation.Smoke;
import com.example.android.notepad.R;
import com.jayway.android.robotium.solo.Solo;
import com.jayway.screens.AddNoteScreen;
import com.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. Эти классы содержат в себе вспомогательные методы, для работы с тестом и экранами. Более детально мы сможем их разобрать в следующих уроках.

Спасибо за внимание.

P.S. Вчера Андрей начал читать новый онлайн тренинг Автоматизация тестирования Android приложений.

Хотите присоединиться к группе и получить первое занятие в записи? Пишите на trainings@software-testing.ru