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

Boundary Value Testing

Boundary Value Testing


Вступление

Boundary Value Testing (техника анализа граничных значений) наиболее известная и простая техника тест дизайна, призванная  помогать рядовому тестировщику выбирать наиболее эффективные значения для тестирования. Эта техника применима на всех уровнях тестирования - unit, integration, system, and system-integration test levels.

Подход

Шаги использования техники анализа граничных значений:

  1. Определите диапазон значений (как правило это класс эквивалентности).
  2. Определите границы диапазонов.
  3. На каждую границу создайте 3 тест кейса - один, проверяющий значение границы, второй на значение ниже границы и третий на значение выше границы.
"выше" и "ниже" границы значения относительные. Например, если мы говорим о границе 6$, то значение "ниже" будет 5$, а значение "выше" 7$. А если мы говорим о границе 6.00$, то значение "ниже" будет 5.99$, а значение "выше" 6.01$.

Примечание: значение "ниже" или "выше" границы может быть другим классом эквивалентности. В этом случае нет смысла создавать дубликаты тест кейсов.

Опять же, будем разбирать эту технику тест дизайна на примерах.


Пример

Анализ граничных значений фокусируется на границах диапазонов потому что как раз на границах обитает больше всего ошибок. Возьмем для примера программу для HR, которую мы разбирали в примерах применения классов эквивалентности. Напомним, что мы тестируем модуль для HR, который определяет брать на работу кандидата или нет, базируясь на возрасте кандидата. Требования такие:

  • 0–16 : Не нанимать
  • 16–18 : Можем нанять только на part time
  • 18–55 : Можем нанять на full time
  • 55–99 : Не нанимать
Представим, что наш девелопер написал такой код по этим требованиям:

      If (applicantAge >= 0 && applicantAge <=16)
                hireStatus="NO";
      If (applicantAge >= 16 && applicantAge <=18)
                hireStatus="PART";
      If (applicantAge >= 18 && applicantAge <=55)
                hireStatus="FULL";
      If (applicantAge >= 55 && applicantAge <=99)
                hireStatus="NO";
Хотя если попробовать предварительно оценить границы диапазонов требований, то сразу видна ошибка - диапазоны пересекаются, накладываются. На самом то деле имелось ввиду:

  • 0–15 : Не нанимать
  • 16–17 : Можем нанять только на part time
  • 18–54 : Можем нанять на full time
  • 55–99 : Не нанимать
Что по поводу значений -3 или 101? Мы можем только догадываться как они будут влиять на нашу программу, но угадывание требований плохая практика :) 

Код для наших требований в итоге должен быть таким:

      If (applicantAge >= 0 && applicantAge <=15)
                hireStatus="NO";
      If (applicantAge >= 16 && applicantAge <=17)
                hireStatus="PART";
      If (applicantAge >= 18 && applicantAge <=54)
                hireStatus="FULL";
      If (applicantAge >= 55 && applicantAge <=99)
                hireStatus="NO";

Следуюя технике граничных значений, значения, на которые мы должны составить тест кейсы, в этом случае будут {-1, 0, 1}, {15, 16, 17}, {17, 18, 19}, {54, 55, 56}, и {98, 99, 100}(не забудьте удалить дубликаты значений :)). Негативные тест кейсы со значения вроде {-42, 1001, FRED, %$#@} могут тоже быть составлены, в зависимости от реализации этого компонента и требований.

Заимствованно с http://w1zle.blogspot.ru

Equivalence Class Testing

Equivalence Class Testing

Вступление

Equivalence Classes (Класс эквивалентности) – это входные (а иногда и выходные) данные, которые обрабатываются приложением одинаково или обработка которых приводит к одному и тому же результату.

Equivalence Class Testing (Тестирование классами эквивалентности) это техника тест дизайна способная резонно уменьшить количество ваших тест-кейсов. Использовать ее можно на всех уровнях тестирования - unit, integration, system, and system-integration test levels.

Как мне кажется эта техника тест дизайна интуитивно понятна и интуитивно применяется каждым тестировщиком, но стоит знать теорию, чтобы осознанно применять технику на практике.

Подход

Использовать эту технику достаточно просто, правила такие:
  1. Определите классы эквивалентности.
  2. На каждый класс эквивалентности сделайте хотя бы 1 тест-кейс.
Примечание: в жизни, как правило, приходится создавать более одного тест кейса на каждый класс эквивалентности, учитывая анализ граничных значений например, но об этом мы будем говорить позже.

Использование классов эквивалентности будем рассматривать на примерах.

Пример.


Представим, что мы тестируем модуль для HR, который определяет брать на работу кандидата или нет, базируясь на возрасте кандидата. Условия такие:
  • 0–16 : Не нанимать
  • 16–18 : Можем нанять только на part time
  • 18–55 : Можем нанять на full time
  • 55–99 : Не нанимать
Стоит ли в этом случае применять exhaustive testing, т.е. должны ли мы протестировать модуль на всех возможных входных данных, на всех возрастах: 0, 1, 2, 3, 4, 5, 6, 7, 8, ..., 97, 98, 99? Если бы имели на это ресурсы, то это был бы неплохой вариант. Либо в случае если девелопер реализовал модуль как нижепередставленный код, то пожалуй тоже бы пришлось тестировать все возраста.

        If (applicantAge == 0) hireStatus="NO";
        If (applicantAge == 1) hireStatus="NO";
        …
        If (applicantAge == 14) hireStatus="NO";
        If (applicantAge == 15) hireStatus="NO";
        If (applicantAge == 16) hireStatus="PART";
        If (applicantAge == 17) hireStatus="PART";
        If (applicantAge == 18) hireStatus="FULL";
        If (applicantAge == 19) hireStatus="FULL";
        …
        If (applicantAge == 53) hireStatus="FULL";
        If (applicantAge == 54) hireStatus="FULL";
        If (applicantAge == 55) hireStatus="NO";
        If (applicantAge == 56) hireStatus="NO";
        …
        If (applicantAge == 98) hireStatus="NO";
        If (applicantAge == 99) hireStatus="NO";
К счастью, наши родные девелоперы так код не пишут (по крайней мере как правило :)). На самом деле для этого модуля мы, как правило, увидим примерно такой код:

If (applicantAge > 0 && applicantAge <=16)
                  hireStatus="NO";
    If (applicantAge > 16 && applicantAge <=18)
                  hireStatus="PART";
    If (applicantAge > 18 && applicantAge <=55)
                  hireStatus="FULL";
    If (applicantAge > 55 && applicantAge <=99)
                  hireStatus="NO";
Поэтому явно видно, что не стоит тестировать все значения 0, 1, 2, ... 14, 15, 16. Более разумно будет протестировать диапазоны каждого условия, что собственно и есть наши классы эквивалентности.:
  1. Класс эквивалентности NO: 0-16.
  2. Класс эквивалентности PART: 17-18.
  3. Класс эквивалентности FULL: 19-55.
  4. Класс эквивалентности NO: 56-99.
Вспомним правила - после определения классов эквивалентности мы должны создать тест кейс с любым значением из диапазона класса эквивалентности. Итого у нас 4 позитивных тест кейса вместо 100. Неплохая оптимизация.

Так же не стоит забывать о не валидных диапазонах, добавим классы эквивалентности и для них:
  1. (-100) – (-1). Значнеие (-100) было взято наугад, по поводу подобных границ лучше консультироваться с девелоперами.
  2. 100-1000. Значнеие (1000) было взято наугад, по поводу подобных границ лучше консультироваться с девелоперами.
  3. 0.1-0.9. Выбрано любое дробное значение входящее в валидный диапазон.
  4. Символы.
  5. Пустой ввод.
  6. ...
Вот собственно и всё. Осталось на каждый класс эквивалентности создать тест-кейс.

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

Для этого лучше рассмотреть следующий пример.


Заимствованно с http://w1zle.blogspot.ru

пятница, 7 декабря 2012 г.

AWK для анализа логов нагрузочного тестирования

AWK для анализа логов нагрузочного тестирования

AWK - утилита предназначенная для простых, механических и вычислительных манипуляций над данными. Довольно несложные операции часто необходимо выполнить над целыми пакетами файлов, а писать для этого программу на одном из стандартных языков программирования является утомительным и, как правило, не очень простым делом. Оптимальное решение проблемы - использование специальной утилиты AWK, включающей в себя не громоздкий и удобный язык программирования, позволяющий решать задачи обработки данных с помощью коротких программ, состоящих из двух-трех строк. 

Небольшой tutorial по awk.

Поля

Каждая сканируемая строка input рассматривается как состоящая из полей, разделенных разделительными символами (по умолчанию - пробел). На поля можно ссылаться из AWK программы следующим образом:
  1. $1 - Первое поле;
  2. $2 - Второе поле;
  3. ... и так далее...
  4. $0 - Ссылается на всю строку целиком.
Строка может содержать максимально до 100 полей.

 Значения переменных

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

Переменные поля

Ссылки на поля $1, $2, ... могут интерпретироваться в качестве переменных, например: $1 = "3" + $2 - первое поле принимает значение второго поля, увеличенного на 3.
$(i+1) - интерпретируется как поле, номер которого зависит от значения переменной i.

Массивы

Допускается использование массивов. Массивы не объявляются, а принимают значения из контекста, например: x[NR] = $0 - элементу массива x, индексированному NR, присваивается обрабатываемая строка.

Регулярное выражение

 Для осуществление поиска в AWK языке допускается использование регулярных выражений, определенных в описании SED, заключенных в``/ /''. Дополнения к использованию регулярных выражений, допускаемые в AWK-языке:
  • "( )" - Скобки допускаются для группирования;
  • " |" - Указание альтернативы "или";
  • " + " - Плюс, стоящий за регулярным выражением означает любую последовательность вхождений этого выражения, начиная с 1;
  • " ? " - Знак вопроса за регулярным выражением означает 0 или 1 вхождений этого выражения;
  • [A-Z] - Допускается сокращенная форма записи для рангов ASCII символов;
  • Установленный порядок выполнения операторов на одном скобочном уровне: "[] * + ? конкатенация |".
Например:
/Olga/ - Указывает на строки, содержащие Olga.
/number[0-9]/ - Указывает на строки, содержащие number0 или number1 или ... number9.

Встроенные функции

length(arg) - Функция длины arg. Если arg не указан, то выдает длину текущей строки.
exp(),log(),sqrt() - Математические функции экспонента, логарифм и квадратный корень.
int() - Функция целой части числа.
substr(s,m,n) - Возвращает подстроку строки s, начиная с позиции m, всего n символов.
index(s,t) - Возвращает начальную позицию подстроки t в строке s. (Или 0, если t в s не содержится.)
sprintf(fmt,exp1,exp2,...) - Осуществляет форматированную печать (вывод) в строку, идентично PRINTF.
split(s,array,sep) - Помещает поля строки s в массив array и возвращает число заполненных элементов массива. Если указан sep, то при анализе строки он понимается как разделитель.

Управляющие структуры

Условное предложение: if ( &lt условие&gt ) &lt предложение&gt
\hskip 1cm [else &lt предложение&gt ]
Предложения цикла:
while ( &lt условие&gt ) &lt предложение&gt
for (&lt выражение&gt ; &lt условие&gt ; &lt выражение&gt )
\hskip 1cm &lt предложение&gt
Например:
for(i=1; i&lt =NF; i++) - Аналогично циклу for в языке ``С''
for (i in array) - Цикл по элементам массива. Но, элементы массива доступны в этом случае в случайном порядке.
break - Немедленный выход из цикла.
continue - Переход к выполнению следующего предложения.
next - Немедленный переход к анализу следующей строки.
exit - Выход из программы (на конец input).
# - Комментарий

И несколько полезных примеров для нагрузочного:

Считаем количество хитов и хостов за час по access

Хиты:
Если реферер не пустой и HTTP=200 тогда считаем.

cat access.log | grep '01/Jun/2011:10:' | grep ' 200 ' | awk '{ if ( $11 != "\"-\"" ) print }' | wc -l

Хосты:
cat access.log | grep '01/Jun/2011:10:' | grep ' 200 ' | awk '{ if ( $11 != "\"-\"" ) print $1}' | uniq | wc -l

в list.txt будет список айпи отсортированный по кол-ву обращений.
просматриваете, находите кто чаще всего обращался к апачу.
cat access.log | awk ' {print $1 }' | sort | uniq -c | sort -nr > list.txt

Использование CSS селекторов вместо Xpath

Использование CSS селекторов вместо Xpath

Сейчас CSS селекторы все больше набирают популярность в использовании и заменяют Xpath селекторы,все это конечно обусловлено скоростью выполнения(у CSS она значительно выше).
Вот небольшая шпаргалка:
Strategy X Path
Sizzle(CSS)
Comments
Element  //div  div  locate first div element
By id //div[@id='eleid']  div#eleid  Locate div with id eleid
By class //div[@class='eleclass']
//div[contains(@class,'eleclass')]
div.eleclass  locate div with class name eleclass if more than one class exist then xpath 2 will be used
By attribute //div[@title='Move mouse here']
  1. div[title=Move mouse here]
  2. div[title^=Move]
  3. div[title$=here]
  4. div[title*=mouse]
you can use match operators for class and id as well, for example div[id^=menu-item]
Child  //div[@id='eleid']/*
//div/h1 
div#eleid >*
div#eleid >h1
Descendant //div[@id='eleid']//h1 div h1  Will work for //div/*/…../h1
By index //li[6] li:nth(5) 6th li element
By content //a[contains(.,'Issue 1164')] a:contains(Issue 1164) Case Sensitive
By Child
  1. //li[a[contains(.,'Issue 1244')]]
  2. //*[./a[contains(.,'Issue 1244')]]
  3. //ul[.//a[contains(.,'Issue 1244')]]
  1. li{a:contains(Issue 1244)}
  2. ul{a:contains(Issue 1244)}
<ul><li> Improved alert on changing the format <a href=”">Issue 1244</a></li>
<li>next sibling</li>…</ul>
<h3>Listing 2</h3>
<ul><li> Improved alert on changing the format <a href=”">Issue 1244</a></li>
<li>next sibling</li>…</ul>
Next Sibling 
  1. //li[preceding-sibling::li[contains(.,'Issue 1244')]]
  2. //ul[preceding-sibling::ul[.//a[contains(.,'Issue 1244')]]]
  1. css=li:contains(Issue 1244) + li
  2. css=ul{a:contains(Issue 1244)} ~ ul
 

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

Selenium WebDriver+Jmeter

Selenium WebDriver+Jmeter


В общем то,для тех кто не в курсе как из Jmeter можно запускать тесты Selenium и будет этот пост.

IDE для Selenium у меня Intellij Idea,поэтому буду показывать на ней.

После написания всех наших тестов на Selenium,остается их только прикрутить к Jmeter,а это куда проще чем кажется.
Т.к у Jmeter есть Junit Sampler,который нам в этом поможет,будем делать все через него.Для начала создадим jar наших Selenium тестов.
В Idea для этого делаем:
1. Project Settings, вкладка Artifacts. Нажимаем [+], в выпавшем меню выбираем JAR.

2. В панели слева - содержимое JAR-файла, в панели справа - содержимое проекта. Перетаскиваем справа налево все, что хотим включить в JAR.
3. Указываем имя для файла и директорию назначения над панелями
3. Нажимаем на  кнопку create manifest под левой панелью, создаем manifest.mf. При этом IDE спросит Main class и classpath для указания в манифесте.(если не подхватятся нужные библиотеки для Selenium WebDriver,то в  classpath укажите путь к selenium-server-standalone.jar )
4. Не забудем поставить галочку "Build on make" над панелями
5. Теперь в меню Build есть команда сборки артефакта
6. PROFIT




Стоит отметить,что наш тестовый класс должен расширять класс TestCase или SeleniumTestCase,чтобы позволить Jmeter их "подобрать".И конечно название тест кейсов должно начинаться с "test".

После того,как мы сгенерировали наш jar файл,нам нужно его положить в
(%JMETER_HOME%/lib/junit)

 После,мы запускаем Jmeter,добавляем в Thread Group наш Junit Sampler,
который сразу подхватит наши тесты.
Осталось только запустить тест и наслаждаться)

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. Эти классы содержат в себе вспомогательные методы, для работы с тестом и экранами.

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

Автоматизации на Robotium

Автоматизации на Robotium 

Начнем с установки нужных средств и написания простого теста.
Что нам для этого понадобится.

1. Установка Java

Как проверить установлена ли нужная версия java? Открываем консоль и пишем
java -version
 Должны получить что-то вроде
1java version "1.6.0_29"
2Java(TM) SE Runtime Environment (build 1.6.0_29-b11)
3Java HotSpot(TM) Client VM (build 20.4-b02, mixed mode, sharing)
Если же получаем
1"java" не является внутренней или внешней
2командой, исполняемой программой или пакетным файлом.
тогда нужно поставить Java)

2. Установка Eclipse IDE

Скачиваем с официального сайта.Запускаем Eclipse

3.Установка Android SDK

Заходим на официальный портал для разработчиков Android. Скачиваем Android SDK и устанавливаем в удобную директорию.

4. Установка нужных платформ

Открываем ADB Manager и устанавливаем нужные платформы.

5. Устанавливаем плагин для Eclipse 

Для этого, на главном меню Eclipse, выбираем Help -> Install new software
Нажимаем Add  и добавляем путь к репозиторию для установки
https://dl-ssl.google.com/android/eclipse/
Устанавливаем Developer Tools
Перезапускаем среду разработки, чтобы продолжить.
Указываем путь к Android SDK в Eclipse IDE. Для этого нажимаем Windows -> Preferences

5. Подготовка тестируемого приложения

За основу возьмем  семпловое приложение из директории семплов Android SDK. Например Notepad.
Для начала создадим проект в EclipseFile -> New -> Android Project
Указываем имя и выбираем Create project from existing sample

Получаем созданный проект. Давайте запустим сборку приложения и проверим его функционал.
Должны получить следующее сообщение в консоле.
1[2012-01-15 11:30:11 - Notepad] ------------------------------
2[2012-01-15 11:30:11 - Notepad] Android Launch!
3[2012-01-15 11:30:11 - Notepad] adb is running normally.
4[2012-01-15 11:30:11 - Notepad] Performing com.example.android.notepad.NotesList activity launch
5[2012-01-15 11:30:11 - Notepad] Automatic Target Mode: launching new emulator with compatible AVD 'Default'
6[2012-01-15 11:30:11 - Notepad] Launching a new emulator with Virtual Device 'Default'
Ждем пока запустится эмулятор.
Это может занять от 1 минуты и иногда до 10ти. Эмулятор самое узкое место в написании программ под Android. В дальнейшем мы поговорим, какие есть альтернативы.
После запуска получаем наше приложение и можем ознакомиться с его функциональными возможностями.

6. Создаем тестовый проект

Создаем тестовый проект, используя проект существующего приложения. Для этого нажимаем правой клавишей мыши на проекте и выбираем Android Tools -> New Test Project
Получили еще один проект, но уже в нем будут храниться наши тесты.

7. Подключаем библиотеку Robotium

Загружаем Robotium jar файл в удобную директорию. Последняя версия, на момент написания статьи, robotium-solo-3.1.jar.
Подключаем библиотеку к тестовому проекту. Правый клик мышкой на тестовом проекте -> Build Path -> Configure Build Path -> Add External JARs...

Все готово для начала автоматизации!


8. Пишем тесты

Создаем первый  тестовый класс в пакете com.example.android.notepad.test. С вот таким содержимым

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();
 }
}
Самый простой тест на добавление новой заметки. Запускаем тест и проверяем результаты.

Много времени уходит на запуск эмулятора. Вы можете попробовать запускать тесты на своем Android телефоне, а так же создавать тесты без привязки к проекту приложения.

За все это мы аплодируем и говорим спасибо Андрею Дзыня.