Перейти к содержимому

Фотография

Уровень абстракции тестов


  • Авторизуйтесь для ответа в теме
Сообщений в теме: 21

#1 LeshaL

LeshaL

    Профессионал

  • Members
  • PipPipPipPipPipPip
  • 1 094 сообщений
  • ФИО:Алексей Лянгузов
  • Город:Saint-Petersburg


Отправлено 29 января 2012 - 18:47

Всем привет!
Продублирую вопрос, заданный мной в фейсбуке (и твитере), т.к. здесь наверное более удобно обсудить различные точки зрения.

Пишу селениумные тесты. Скажите плз, какой из вариантов на ваш взгляд выглядит лучше и будет более удобен на практике (и для написания тестов и для их поддержки). Учтите, что тесты пишутся в среде, где все умеют так или иначе программировать.
=============
http://pastebin.com/Wc6K4z4K
=============
1) 1й вариант - то что есть сейчас. Требует компромисса между скоростью написания и читабельностью. Неплохо приспособлен к изменениям, но требует определенных затрат на это.
2) 2й вариант требует затрат на фреймворк, без выигрыша по скорости написания, но с превосходной читабельностью и замечательной реакцией на изменения.
3) 3й вариант - почти "сырой" - т.е. почти никакой не нужен фреймворк и достаточно быстрое написание тестов. Но никакая читабельность и солидные затраты на изменения.

----
На данный момент все подходы применимы, некоторые в экспериментальном варианте. Нужно выбрать. Прошу мнений.
Есть еще подвариант второго варианта
http://pastebin.com/kDf6e9xh

Вообще второй вариант задуман для отвязки проверок от используемого фрейворка (junit, testng etc) и ради возможности следить за тем, чтобы не было тестов без проверок и еще ради возможности найти все ошибки сразу, а не падать на первом же ассерте. Хотя при написание тестов и проверок требует больших затрат.
  • 0
Regards,
Alexey

#2 vaha

vaha

    Новый участник

  • Members
  • Pip
  • 22 сообщений
  • ФИО:Илья

Отправлено 29 января 2012 - 20:03

Скорость написания в третьем случае иллюзорна - быстро будет написан первый тест(пока вилларибо пишет фреймворк, виллабаджо наклепала 3 теста), потом копипаст утянет в пучину.
Первый вариант кстати лично меня отталкивает лишь наличием приведения - из-за снижения читабельности и рассеивания внимания +)
Второй вариант конечно заманчив - но решительность при выборе в его пользу зависит от сложности системы в целом.
Я бы начал со второго варианта, но не слишком бы убивался пытаясь придерживаться его - написал бы некоторое кол-во разноплановых тестов, а потом бы уж точно определился со стилем. Да и вообще бы на первых порах написания фреймворка не советовал наращивать "критическую массу" тестов.
  • 0

#3 LeshaL

LeshaL

    Профессионал

  • Members
  • PipPipPipPipPipPip
  • 1 094 сообщений
  • ФИО:Алексей Лянгузов
  • Город:Saint-Petersburg


Отправлено 29 января 2012 - 20:30

Скорость написания в третьем случае иллюзорна - быстро будет написан первый тест(пока вилларибо пишет фреймворк, виллабаджо наклепала 3 теста), потом копипаст утянет в пучину.
Первый вариант кстати лично меня отталкивает лишь наличием приведения - из-за снижения читабельности и рассеивания внимания +)
Второй вариант конечно заманчив - но решительность при выборе в его пользу зависит от сложности системы в целом.
Я бы начал со второго варианта, но не слишком бы убивался пытаясь придерживаться его - написал бы некоторое кол-во разноплановых тестов, а потом бы уж точно определился со стилем. Да и вообще бы на первых порах написания фреймворка не советовал наращивать "критическую массу" тестов.

В первом варианте приведения вроде можно избежать, как сделать я придумал только вот сейчас отвечая на вопрос. Завтра попробую. Да и возникают они только после метода open общего для всех страниц. А метод используется редко сам по себе.
Ну и конечно его можно избежать, разбив на две строки. Такова уж неповоротливая джава.
И так и есть, пока есть представители всех 3х вариантов тестов. 3й я стараюсь переводить в первый. Второй экспериментальный, сделал на выходных и пока не советовался с программистами, насколько он им будет удобен. В том-то и дело, что он заманчивый (с точки зрения тестировщика), но есть некоторые моменты, которые меня смущают.
  • 0
Regards,
Alexey

#4 Wolonter

Wolonter

    Постоянный участник

  • Members
  • PipPipPip
  • 205 сообщений
  • ФИО:Макс
  • Город:Екатеринбург


Отправлено 30 января 2012 - 06:59

1) 1й вариант - то что есть сейчас. Требует компромисса между скоростью написания и читабельностью. Неплохо приспособлен к изменениям, но требует определенных затрат на это.
2) 2й вариант требует затрат на фреймворк, без выигрыша по скорости написания, но с превосходной читабельностью и замечательной реакцией на изменения.
3) 3й вариант - почти "сырой" - т.е. почти никакой не нужен фреймворк и достаточно быстрое написание тестов. Но никакая читабельность и солидные затраты на изменения.


В свое время я использовал все варианты.
Сейчас остановились на первом. Удобно вешать дополнительные ассерты в нестандартных случаях.

От второго отказались из за неудобства поддержки - по статистике тратится больше времени на дебаг теста.
Третий - нереально большие затраты на поддержку, быстро только писать, жить с этим нельзя.
  • 0

#5 Boltick

Boltick

    Специалист

  • Members
  • PipPipPipPipPip
  • 596 сообщений
  • ФИО:Алексей
  • Город:планета Земля

Отправлено 30 января 2012 - 08:42

1) 1й вариант - то что есть сейчас. Требует компромисса между скоростью написания и читабельностью. Неплохо приспособлен к изменениям, но требует определенных затрат на это.
2) 2й вариант требует затрат на фреймворк, без выигрыша по скорости написания, но с превосходной читабельностью и замечательной реакцией на изменения.
3) 3й вариант - почти "сырой" - т.е. почти никакой не нужен фреймворк и достаточно быстрое написание тестов. Но никакая читабельность и солидные затраты на изменения.

----
На данный момент все подходы применимы, некоторые в экспериментальном варианте. Нужно выбрать. Прошу мнений.

Исторически сложилось (на протяжении последних 3-4ех лет), что используем вариант 2. Вариант 3 используется только для того, чтобы быстро что-то проверить и выкинуть в мусорку, т.к. в долгосрочной перспективе появляюся большие проблемы с саппортом.
  • 0
Алексей Булат
Про Тестинг

#6 checo

checo

    Опытный участник

  • Members
  • PipPipPipPip
  • 400 сообщений
  • Город:Н.Новгород

Отправлено 30 января 2012 - 09:19

Вариант #1 позволяет править отдельные тесты "на лету", не ломая всего остального.
Вариант #2 применять легко и приятно, если речь идет о проверках, многократно повторяемых в разных тестах (например, предварительная подготовка среды, проверка статусов и т.п.). Но полностью перейти на него просто не удастся, тесты обычно бывают слишком разные.
  • 0

#7 Dzmitry_by

Dzmitry_by

    Новый участник

  • Members
  • Pip
  • 10 сообщений
  • ФИО:- - -

Отправлено 03 февраля 2012 - 15:26

ИЗВИНИТЕ МНОГО БУКВ!!!!!!!

Я почему-то так задумался над этим вопросом - и в течении нескольких дней записывал мысли по этому поводу.

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

Читаемость кода для посторонних людей не знакомых с программированием я не считаю главным условием. При желании для любого хорошего кода можно сконструировать мета-обёртку в любом виде, будь то html, либо слова из обычного человеческого лексикона. Тогда каждое действие будет своего рода кнопкой - при нажатии на которую произойдёт действие. Вы можете дать набор таких кнопок пользователю - и единственной вашей по настоящему серьёзной проблемой будет поддержание того, что эти кнопки будут действительно делать то, для чего они предназначены. А также между делом - нужно будет разрабатывать новые кнопки.

Тестировщик - это не обычный пользователь. Тестировщику в тесте не нужна большая кнопка "GO" а после этого кнопка "CHECK_THAT_ALL_OK". Тестировщику нужно дать такую кнопку - на которую можно нажать сто разными способами, либо сто разных кнопок. Либо эти кнопки должны делать какие-то совсем элементарные вещи - вроде клика на элемент, которые не могут вызвать двусмысленности.
Вы кончено можете объединять такие элементарные кнопки в какие-то повторяющиеся действия - и давать тестировщику просто такие коллекции действий. Но как показывать лично мой опыт - без элементарных кнопок кликнуть или перетащить, или проскроллить - не обойтись.

PS извините если что-то не правильно написал - спасибо за поправки.

Что касается вообще кода фреймворка, качественый код может выглядеть по-разному, но не качественному коду как правило характерны следующие черты:
  • Жёсткость – трудность внесения изменений в код.
  • Хрупкость – склонность программы к появлению многих багов в неожиданных местах, если в каком-то одном месте вносятся изменения.
  • Иммобилити – система содержит части, используемые другими системами, и существует риск того, что внесение изменений в существующую программу может неожиданным образом повлиять на другие.
  • Вязкость кода – (вязкость софта и вязкость окружения) -
    вязкость софта - выражается в том, что при необходимости внесения изменений – как правило существует несколько способов внести данное изменение. Существуют способы внесения изменения сохраняя существующий дизайн, есть способы внесения изменения с грубым нарушением существующего дизайна – хаки. Если вносить изменение при помощи хака проще чем вносить изменение следуя принципам существующего дизайна – то в данном случае можно говорить что присутствует вязкость софта.
    Вязкость окружения – неэффективные и медленные средства разработки. (возможно – привязка к одной определённой операционной системе).
  • Ненужная сложность программы (овердизайн) – код содержит неиспользуемые, ненужные элементы, код сложен к пониманию того как он функционриует.
  • Неоправданное копирование кода – (копи-паста)
  • Непрозрачность кода – код “разворачивающийся по спирали” – со временем становится всё более и более непрозрачным.

(Prentice Hall PTR - Agile Principles Patterns and Practices in CSharp)

Я позволю себе скопирвоать ваши три примера кода:

вариант 1
============= Variant 1 =========================
1a)
public void loginWithCorrectUser(){
  IndexPage indexPage = loginPage.open().login(new CorrectUser1());
  assertEquals("Check that we are on correct page",
    loginPage.getTitle(), driver.getTitle());
  assertTrue("Check we are actually loged in", indexPage.isLoggedIn());
}
1b)
public void testLogout(){
  LoggedInPage inPage = ((LoginPage)loginPage.open()).login();
  LoginPage loginPage2 = inPage.logout();
  assertEquals("Check that we are on the correct page",
    loginPage.getUrl(), loginPage2.getUrl());
  assertTrue("Check that login button exists",
    loginPage.isNotLoggedIn());
}

вариант 2
============= Variant 2 =========================
2a)
public void loginWithCorrectUser(){
  User.newUser(UserTypes.EXISTENT)
    .doLogin()
      .checkLoggedIn(true);
}
2b)
public void testLogout(){
  User.newUser(UserTypes.EXISTENT)
    .doLogin()
      .checkLoggedIn(true)
    .doLogout()
      .checkLoggedIn(false)
      .checkLoggedOut(true);
}

вариант 3
============= Variant 3 =========================
3a)
public void loginWithCorrectUser(){
  User user1 = User.createNewUser();
  loginPage.type("username", user1.getName());
  loginPage.type("password", user1.getPass());
  loginPage.click("loginButton");
  IndexPage indexPage = PageFactory.initElements(driver, IndexPage.class);
  assertTrue("Check we are actually loged in", indexPage.isElementPresent(indexPage.linkLogout));
}
3b)
public void testLogout(){
  User user1 = User.createNewUser();
  loginPage.type("username", user1.getName());
  loginPage.type("password", user1.getPass());
  IndexPage indexPage = loginPage.click("loginButton").click("logoutLink");
  LoginPage loginPage2 = PageFactory.initElements(driver, LoginPage.class);
  assertEquals("Check that we are on the correct page",
    loginPage.getUrl(), loginPage2.getUrl());
  assertTrue("Check that login button exists",
    loginPage.isElementPresent("loginButton"));
}

И оценить, насколько трудно будет внести следующие изменения в данный код:
  • Изменились параметры корректного пользователя
  • Изменилась форма логина: нужно ввести дополнительный код (инвайт)
  • Изменилась проверка того, что пользователь успешно залогинился

Изменились параметры корректного пользователя

Жёсткость: 0 штрафных очков за вариант 1. (можно внести изменение в объект CorrectUser1, не меняя приведенного кода). То-же самое для второго варианта. В третьем случае – данные для логина получаются в виде строки одноимёнными методами от объекта user1, соответственно – как и в первых двух случаях – нужно менять объект user1 – в приведенный код в примерах изменений вносить не нужно. Следование Open/Closed принципу (SOLID).

Хрупкость: предположим, что данные о логине и пароле хранятся в виде текстового файла в кодировке UTF8. При создании объекта user – данный файл считывается и из него извлекаются занчения. Какой-то злодей изменил значение и сохранил файл в формате UTF8 c BOM. Именно в контексте замены старого логина и пароля на новое значение. Не повлияет ли это на программу? Если внезапно выяснится, что в имени логина появился? - я думаю что это штрафной балл за хрупкость. Для всех трёх случаев данные о логине и пароле в той либо иной степени хранятся в объекте user. Если для инициализации объекта user используется ненадёжный механизм – источник хрупкости будет одинаков.

Иммобилити: Если объект CorrectUser1() содержит только данные о логине и пароле – то всё ок. Если же он содержит какие-то связанные со старыми значениями логина пароля (например телефон, соответствующий старому пользователю) и есть какие-то системы которые полагают, что обращаясь к CorrectUser1() они получат данные от старого значения логина и пароля – то можно заработать штраф за иммобильность. Для трёх случаев одинаково.
Вязкость софта: - признайтесь честно – класс от которого создаётся CorrectUser1() имеет-ли в своём дизайне какие-либо механизмы для использования разных значений логина и пароля? Либо эти значения захардкожены? Предусматривает-ли ваш дизайн гибкую систему подмены криденшлов, или проще сделать хак – поправить напрямую в коде? Либо дизайн ваших тестов не предполагает выделение отдельных тестовых данных, и это соответствует дизайну, что логин и пароль хранятся в виде final static к примеру?

Ненужная сложность программы: покажите код каждого из приведенных выше примеров своему товарищу, в контексте изменения данных о логин-пароль. Трудно ли с первого взгляда точно сказать, где именно и какие именно изменения нужно внести? Сколько времени займёт у не знакомого с вашим фреймворком девелопера корректно внести данное изменение?

Неоправданное копирование кода: в контексте изменения только лишь пароля и логина – подозреваю, что для всех трёх приведенных выше примеров – данные о логине и пароле можно изменить примерно в одном месте – и данное изменение автоматически будет «подхвачено» остальным кодом. Нигде не заметно явного использования магического значения строк.

Непрозрачность кода: Во всех трёх случаях, рассматривая только приведенные выше три варианта, можно сказать, что в контексте изменения логина и пароля - код непрозрачный. Единственно только, что в третьем случае видно, что у объекта можно получить логин и пароль соответственными методами, во всех остальных случаях – просто передаётся объект типа пользователь в соответствующий метод. 

Изменилась форма логина: нужно ввести дополнительный код (инвайт)

Жёсткость: Для всех трёх вариантов менять придётся или код самого теста (вариант 3 – нужно вставить дополнительное действие по вводу кода инвайта), или код метода логин. Если в третьем случае всё понятно – нужно вносить дополнительное действие после type логина и пароля, и такое действие нужно добавить везде, где используется данный код. Соответственно если данный фрагмент кода логин+пароль+клик_отправить используется ещё во многих местах, и в своё время вставлялся при помощи копи-пасты – жесткость будет увеличиваться пропорционально количеству таких фрагментов. В первом варианте нужно будет как-то изменить работу метода login. Для второго варианта – то же самое, что и для первого варианта.

Хрупкость – сложно оценить, не имея перед глазами код который выполняет метод login. Очень возможно, что внутри метода login содержится код из третьего варианта.

Иммобилити: на мой взгляд примером иммобилити в данном случае может быть то, что метод логин одинаково используется для разных приложений. И вот после того, как в одном приложении добавилась форма ввода дополнительного кода инвайта, метод логин резко перестаёт быть универсальным методом для всех приложений, как было недавно.

Вязкость софта: …сложно оценить. В третьем случае – добавление дополнительного действия вполне вписывается в существующий дизайн. Для первого и второго вариантов – немного сложнее. Для первого варианта можно сделать такой хук: после того как старый метод отработает и ввёдет только логин и пароль – и нажмёт на кнопку отправить, допустим – что приложение вернёт обратно страницу приложения – с сообщением о том, что введённые данные не корректны. Но при этом введённые ранее логин и пароль останутся на странице. В данной ситуации непосредственно в тест можно дописать ещё одно действие ввода кода инвайта и заново нажимания на кнопку отправить. Код начнёт выглядеть примерно так:
public void loginWithCorrectUser(){
  IndexPage indexPage = loginPage.open().login(new CorrectUser1());
/*additional action to enter invite code*/
huk.enterInviteCode().login(new CorrectUser1());
  assertEquals("Check that we are on correct page",
    loginPage.getTitle(), driver.getTitle());
  assertTrue("Check we are actually loged in", indexPage.isLoggedIn());
}
Если по каким-либо причинам, например для экономии времени такой способ окажется более предпочтительный – налицо вязкость софта.

По критериям Ненужной сложности и Непрозрачности – всё аналогично первому случаю.

Изменилась проверка того, что пользователь успешно залогинился

Жёсткость: Для первого варианта придётся явным образом менять механизм проверки – и механизм этот придётся менять в каждом месте где он был скопирован. И за каждое такое изменение больше одного раза можно начислять по одному штрафному очку за жёсткость кода. Аналогично для третьего варианта. Для второго варианта – нужно будет менять поведение метода checkLoggedIn(true) – хорошо, если будет возможность переопределить этот метод, плохо, если этот метод нужно будет заменить другим.

Иммобилити – Как писалось выше – если не возможно переопределить метод checkLoggedIn(true) потому что он используется какими-то другими системами – кроме штрафного очка за жёсткость можно получить ещё и штрафное очко за иммобильность. Для первого и третьего приведенных вариантов – штраф за иммобильность будет если данные фрагменты используются кроме текущего сьюта, также в нескольких посторонних, и изменение метода проверки корректности успешного логина может повлиять на корректность работы других тестов для других приложений, хотя для конкретно этого – всё будет ок.

Вязкость софта в контексте изменения проверки успешности залогинивания может быть показана на примере второго варианта: Если для того, чтобы поменять проверку того, что пользователь успешно залогинился – проще всего будет вставить такой вот хук:
public void loginWithCorrectUser(){
User.newUser(UserTypes.EXISTENT).doLogin().checkLoggedIn(false);
Assert (“additional check”, blnExpected, blnActual);
}
Вместо того, чтобы переопределить checkLoggedIn метод – то это признак вязкости софта.

И если вы всё-же пойдете на такой шаг – вы ещё заработаете штрафное очко за Ненужная сложность программы – получается что у вас используется checkLoggedIn(false); - метод фактически вызывается, но полезной проверки не производит. Проверте, сколько ещё у вас в коде может быть методов которые выполняются с подавлением ошибки. Либо внутри себя содержащие действия – которые не могут быть выполнены, но сообщение об ошибке о которых подавляется.

И снова – с точки зрения непрозрачности кода – второй вариант наименее удачный, так как он только содержит метод checkLoggedIn(true);, но как именно происходит проверка – неизвестно. Всё будет хорошо, пока данный участок кода работает без ошибок. Но когда ошибка произойдёт – и данный метод вернёт fail – сможете ли вы точно сказать, почему именно не прошла проверка checkLoggedIn(true) только имея перед собой код из второго варианта?
  • 1

#8 LeshaL

LeshaL

    Профессионал

  • Members
  • PipPipPipPipPipPip
  • 1 094 сообщений
  • ФИО:Алексей Лянгузов
  • Город:Saint-Petersburg


Отправлено 05 февраля 2012 - 17:15

...

Спасибо за столь детальный анализ. На мой взгляд не хватает обобщенного вывода в конце, по которому можно было бы принять решение.
И конечно, данный анализ чрезмерно сложен для такой задачи. В качестве пояснения скажу, что весь код модифицируем так как этого хочется (в том числе и код приложения); а данные (например имена пользователей) заточены на специальное тестовое наполнение базы. В отличие от абстрактного ПО, рассчитанного на массового пользователя у этих тестов и фреймворка ограниченное и однозначное использование во вполне однозначных начальных условиях.

Что касается ваших примеров:
1. Изменились параметры корректного пользователя
Есть (или будут) такие тесты, которые это проверяют. Поэтому весьма штатная ситуация, предусмотренная реализацией типа User. Для всех трех вариантов тестов это не проблема. Наверное следует отметить, что в данном случае объект User - это не объект пользователя, зарегистрированного в системе, а некий тестовый субъект решивший зарегистрироваться или залогиниться в систему.

2. Изменилась форма логина: нужно ввести дополнительный код (инвайт)
Тут два подхода. Наиболее логичным, на мой взгляд, является изменение типа User, у которого помимо атрибутов "имя" и "пароль" будет еще и "инвайт", т.к. этот "инвайт" также является объектом для написания нескольких тестов.
Второй подход - это создание отдельного типа Invite, который в паре с пользователем будет передаваться в метод login. Можно написать два метода login(User u) и login(User u, Invite in), сохраняя неизменными те тесты, где нам неинтересно значение поля Invite. Очевидно, что первый укороченный вариант метода login будет только создавать внутри правильный Invite и вызывать второй метод, как это обычно и делается. Здесь третий вариант проигрывает, т.к. не имеет отдельного метода и возникнет необходимость менять все тесты на эту функциональность.

3. Изменилась проверка того, что пользователь успешно залогинился
Здесь вообще следует отметить, что на практике (при тестировании других объектов) зачастую возникает необходимость делать одинаковые проверки в разных тестах и логично при этом все такие проверки (asserts) выносятся в приватный метод внутри тестового класса. Поэтому, что в первом, что в 3м варианте все-равно будет метод checkIsLoggedIn, в который и надо будет внести изменения. Во втором варианте тестов этот метод принадлежит не тесту, а типу User.
  • 0
Regards,
Alexey

#9 LeshaL

LeshaL

    Профессионал

  • Members
  • PipPipPipPipPipPip
  • 1 094 сообщений
  • ФИО:Алексей Лянгузов
  • Город:Saint-Petersburg


Отправлено 05 февраля 2012 - 18:06

По результатам общения и размышлений пришел к выводу, что надо реализовывать вариант №2.
Объясню почему.
1) Он дает возможность более просто писать тесты, оперирующие с разными наборами данных, но с примерно одинаковым алгоритмом действий.
2) Оперирует объектами бизнес логики приложения отдаляясь от конкретной реализации страниц. Страницы же отвечают за предоставление информации об элементах и их содержимом.
3) При реализации этого подхода, вариант №1 остается доступным.
4) Более просто проследить сценарии, описанные в спецификациях.
5) Позволяет более "чисто" писать именно сценарные тесты с несколькими проверками по ходу дела и оперирующими несколькими объектами (а не только пользователем, как в примере).
6) Даёт простую возможность переиспользовать методы объектов как предварительные акции и без всяких изменений. Надо только убрать методы "checkXXX".
7) Очень важно то, что он даёт возможность следить за тем, чтобы в методах был бы вызван хоть раз хоть один check, в отличие от стандартного unit теста, который будет пройден, даже если в нём нет ни одной проверки.
8) Позволяет использовать проверки неоднократно (не в рамках одного теста, а "шарить" их между разными тестовыми классами).
9) Позволяет проверить результат всех проверок (asserts) в тесте, в отличие от junit, где падение происходит на первой же проверке. Очень удобно при отладке тестов.
10) Позволяет делать негативные проверки без перехвата AssertError (или что там используется) в каждом тесте, где есть такая необходимость.

Что касается возможности вешать дополнительные asserts, то она ровно такая же как и в первом варианте.
Что касается сложности отладки или поиска неисправности во втором варианте - зависит от того как выдаётся информация при ошибке.
Что касается того, что все перевести на вариант №2 не получится, ну и ладно. Вариант №1 меня тоже устраивает, а вариант №3 при появлении будет переводиться в вариант №1 или №2. Вообще оптимальным при написании нового теста кажется такая последовательность: пишется тест в варианте №3 (можно опустить) и потом переделывается в №1, при появлении большего количества тестов на данную функциональность всё рефакторится к виду №2.
  • 0
Regards,
Alexey

#10 OVA

OVA

    Опытный участник

  • Members
  • PipPipPipPip
  • 405 сообщений
  • ФИО:Высоцкий Сергей Павлович
  • Город:Новосибирск

Отправлено 06 февраля 2012 - 04:10

№2 еще бы допилить, чтобы ассерты были только в одном тесте, ну и в идеале - один ассерт = один тест.
  • 0

#11 LeshaL

LeshaL

    Профессионал

  • Members
  • PipPipPipPipPipPip
  • 1 094 сообщений
  • ФИО:Алексей Лянгузов
  • Город:Saint-Petersburg


Отправлено 06 февраля 2012 - 06:14

№2 еще бы допилить, чтобы ассерты были только в одном тесте, ну и в идеале - один ассерт = один тест.

Зачем? Зачем я буду следовать синтетическому ограничению, которое в основном советуют люди, которые пишут книги, а не тесты?
Возможно (хотя я не верю) в "настоящих" юнит тестах такое ограничение имеет смысл. Но у меня же UI тесты имитирующие действия пользователя.

В моих тестах будет столько проверок, сколько требуется. Я буду проверять прекондишены перед запуском основного действия, например для уменьшении времени при неуспешном выполнении подготовительного действия. Более того, далее стоит задача покрывать сценарии, описанные в спеке, т.е. там сделал действие, проверил, сделал, проверил итд в одном тесте.
Или вот например:
.doLogout()
      .checkLoggedIn(false)
      .checkLoggedOut(true);
имеет две проверки после действия. Можно сделать одну, так чтобы второй метод вызывал первый и в данном случае это прокатит, но в другом случае будет сложнее не запутаться, чем вызвать несколько проверок.

Честно говоря я большой непоклонник слепого следования сомнительным "бест практисам".
  • 0
Regards,
Alexey

#12 OVA

OVA

    Опытный участник

  • Members
  • PipPipPipPip
  • 405 сообщений
  • ФИО:Высоцкий Сергей Павлович
  • Город:Новосибирск

Отправлено 06 февраля 2012 - 09:13

Зачем? Зачем я буду следовать синтетическому ограничению, которое в основном советуют люди, которые пишут книги, а не тесты?
Возможно (хотя я не верю) в "настоящих" юнит тестах такое ограничение имеет смысл. Но у меня же UI тесты имитирующие действия пользователя.

Я не предлагаю следовать. Идеал он для того чтобы к нему стремиться. Мой опыт подсказывает что много ассертов в тесте зачастую хорошая эвристика для определения тестов на рефакторинг. Как правило такие тесты первые кандидаты в очереди на редизайн. Но мой опыт на то и мой, что не ваш.

Более того, далее стоит задача покрывать сценарии, описанные в спеке, т.е. там сделал действие, проверил, сделал, проверил итд в одном тесте.

А откуда такая задача? Это в принципе очень непродуктивный подход к дизайну автоматических тестов.
  • 0

#13 Boltick

Boltick

    Специалист

  • Members
  • PipPipPipPipPip
  • 596 сообщений
  • ФИО:Алексей
  • Город:планета Земля

Отправлено 06 февраля 2012 - 10:29


Более того, далее стоит задача покрывать сценарии, описанные в спеке, т.е. там сделал действие, проверил, сделал, проверил итд в одном тесте.

А откуда такая задача? Это в принципе очень непродуктивный подход к дизайну автоматических тестов.

Оппа... И чем же он не продуктивен? Как вы собираетесь писать скрипт на проверку некоевого сценария состоящего допустим из 7-8 шагов (а иногда и 10-15)?
Ради Бога, не подумайте, что это наезд. Просто хочется понять, где ошибка, в случае если я ошибаюсь, т.к. сам делаю так, как описывает Алексей.

Заранее спасибо
  • 0
Алексей Булат
Про Тестинг

#14 OVA

OVA

    Опытный участник

  • Members
  • PipPipPipPip
  • 405 сообщений
  • ФИО:Высоцкий Сергей Павлович
  • Город:Новосибирск

Отправлено 06 февраля 2012 - 10:50

Оппа... И чем же он не продуктивен? Как вы собираетесь писать скрипт на проверку некоевого сценария состоящего допустим из 7-8 шагов (а иногда и 10-15)?

Давайте начнем с простых вопросов.
Вам точно нужно проверять именно этот сценарий? Если да, то почему. Ответ "мне так начальник сказал" это плохой ответ.
Что происходит в ходе теста?
Что бы вы хотели узнать в ходе теста?
Точно ваш сценарий это самый простой и удобный способ получить ответы на предыдущие два вопроса?

В большинстве случаев перекладывание мануального сценария на робота это не дизайн теста под робота, а перекладывание с больной головы на еще более больную.
Если вам нужно писать тесты на какую-то функциональность - пишите тесты на нее и только на нее, сценарии тут в большинстве случаев лишь бесполезная трата времени и усложнение интерпритации теста (к тому же добавление лишних точек провала).
Если вам нужно писать тесты на workflow, пишите машину, которая будет уметь генерировать workflow, а не проходить один и тот же сценарий из раза в раз.
Если у вас есть какие-то более интересные вопросы, на которые куда проще отвечать при помощи большого и страшного компьютера - придумывайте хорошие тесты которые будут на эти вопросы отвечать.
  • 0

#15 Boltick

Boltick

    Специалист

  • Members
  • PipPipPipPipPip
  • 596 сообщений
  • ФИО:Алексей
  • Город:планета Земля

Отправлено 06 февраля 2012 - 12:35

Давайте начнем с простых вопросов.
Вам точно нужно проверять именно этот сценарий? Если да, то почему. Ответ "мне так начальник сказал" это плохой ответ.
Что происходит в ходе теста?
Что бы вы хотели узнать в ходе теста?
Точно ваш сценарий это самый простой и удобный способ получить ответы на предыдущие два вопроса?

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


Хм... звучит логично... однако есть кое что для уточнения.

Есть случаи использования (use cases), которые просто обязаны работать. Именно по ним мы и пишем длинные тестовые сценарии.

Ну, например, надо проверить, что новосозданный залогиненный пользователь может сделать заказ в магазине. Получаем сценарий вида:
1. создать пользователя
2. залогиниться
3. выбрать тестовый товар и положить его в корзину
4. зайти в корзину, проверить что заказ появился в корзине
5. выбрать способ доставки
6. оформить заказ
7. перейти на страницу контроля заказов и проверить, что заказ появился

В принципе, автоматизированно каждый шаг можно проверить и по отдельности. Однако, много раз встречал ситуацию, когда отдельно все работает, а вместе почему-то нет.
Если продолжать филосовствовать дальше, то можно сказать, что это своего рода системный тест на базе случаев использования (use cases), в то время как отдельные тесты - это аналог модульных тестов.
Такого рода сценарии мы называем end-2-end тестами и проводим их при каждой выдаче приложения в тест. Получается, что это автоматизированный Acceptance testing.

P.S. Но я не говорю, что пишу только end-2-end тесты. Помимо их есть и тесты на фунциональность.


Походу можно новую тему открывать :) про уровни автоматизации тестирования :)
  • 0
Алексей Булат
Про Тестинг

#16 LeshaL

LeshaL

    Профессионал

  • Members
  • PipPipPipPipPipPip
  • 1 094 сообщений
  • ФИО:Алексей Лянгузов
  • Город:Saint-Petersburg


Отправлено 06 февраля 2012 - 12:43

Если вам нужно писать тесты на workflow, пишите машину, которая будет уметь генерировать workflow, а не проходить один и тот же сценарий из раза в раз.

Интересная идея, надо обдумать. Хотя она не отменяет прохождение по специфицированным (читай acceptance) сценариям. А тестирование сценариев, конечно же, не отменяет функционального тестирования.
  • 0
Regards,
Alexey

#17 LeshaL

LeshaL

    Профессионал

  • Members
  • PipPipPipPipPipPip
  • 1 094 сообщений
  • ФИО:Алексей Лянгузов
  • Город:Saint-Petersburg


Отправлено 06 февраля 2012 - 12:53

Походу можно новую тему открывать :) про уровни автоматизации тестирования :)

Только что обсуждали эти уровни с коллегами. Сошлись для начала на 3х (это для GUI тестирования только)
1) PreCommitTests - маленький набор, поддерживаемый в "зеленом" состоянии программистами и ими же используемый перед комитом.
2) ReqTests - набор тестов написанных по спеке, покрывающий как отдельные функциональные требования, так и описанные сценарии. Второе в будущем может трансформироваться в отдельный Acceptance Tests
3) OtherTests - тесты с разными наборами данных, негативные тесты (неописанные в спеке) и прочие тесты (например необходимые для воспроизведения дефекта и его верификации).

Если решим запускать в CI после каждого комита какие-то тесты, то вероятно появится еще поднабор, состоящий из 1 и части 2.
Понятно, что один тест может входить в несколько тестовых наборов.
  • 0
Regards,
Alexey

#18 Wolonter

Wolonter

    Постоянный участник

  • Members
  • PipPipPip
  • 205 сообщений
  • ФИО:Макс
  • Город:Екатеринбург


Отправлено 07 февраля 2012 - 04:35

Только что обсуждали эти уровни с коллегами. Сошлись для начала на 3х (это для GUI тестирования только)
1) PreCommitTests - маленький набор, поддерживаемый в "зеленом" состоянии программистами и ими же используемый перед комитом.


Жутко интересно, как вы ограничили размер набора. Выбрали самое важное что укладывается в n минут? GUI тесты имеют свойство идти долго. Если не секрет, сколько идет этот зеленый набор?
  • 0

#19 LeshaL

LeshaL

    Профессионал

  • Members
  • PipPipPipPipPipPip
  • 1 094 сообщений
  • ФИО:Алексей Лянгузов
  • Город:Saint-Petersburg


Отправлено 07 февраля 2012 - 05:41


Только что обсуждали эти уровни с коллегами. Сошлись для начала на 3х (это для GUI тестирования только)
1) PreCommitTests - маленький набор, поддерживаемый в "зеленом" состоянии программистами и ими же используемый перед комитом.


Жутко интересно, как вы ограничили размер набора. Выбрали самое важное что укладывается в n минут? GUI тесты имеют свойство идти долго. Если не секрет, сколько идет этот зеленый набор?

Да никак пока не ограничили. Сейчас тесты идут порядка 3х минут ибо их не много еще. Добрая половина из них уедет в другие наборы, когда я наконец засетаплю все через хадсон. Программисты обычно не делают много комитов за день (имеется ввиду в интеграционное пространство) и пару раз запустить такой набор - не проблема, тем более, что это их инициатива изначально.
  • 0
Regards,
Alexey

#20 OVA

OVA

    Опытный участник

  • Members
  • PipPipPipPip
  • 405 сообщений
  • ФИО:Высоцкий Сергей Павлович
  • Город:Новосибирск

Отправлено 07 февраля 2012 - 05:42

В принципе, автоматизированно каждый шаг можно проверить и по отдельности. Однако, много раз встречал ситуацию, когда отдельно все работает, а вместе почему-то нет.
Если продолжать филосовствовать дальше, то можно сказать, что это своего рода системный тест на базе случаев использования (use cases), в то время как отдельные тесты - это аналог модульных тестов.
Такого рода сценарии мы называем end-2-end тестами и проводим их при каждой выдаче приложения в тест. Получается, что это автоматизированный Acceptance testing.

Если покрыть все функции довольно плотно, то шансов на то что вместе оно не работает будет мало.
Да, согласен, риски еще останутся, но статичный сценарий для автоматических тестов их никуда не уберет. Мы просто прочертим себе дорожку по минному полю, где мины будут находиться легко и просто.
Я ничего не имею против простых сценариев. Т.к. они простые - они быстро выполняются и их проще поддерживать/дописывать/мониторить покрытие. В ряде случаев достаточно простые сценарии это очень дешевый способ отскочить. Но с усложнением сценария все эти бонусы начинают теряться.
Т.е. в вашем сценарии сразу можно выкинуть логин и всю навигацию - лучше проверять их отдельно, а остальные тесты делать без них.
Потом сделать пачки тестов для манипуляций с корзиной (небольшие, легковесные, легко рандомизируемые).
Потом сделать пачки тестов для оплаты разных корзин (нам же не обязателен UI чтобы получить точно такую же корзину?).
Это будет дешево и сердито. И придется постараться чтобы оправдать чем-то кроме паранойи наличие теста в котором будет производиться склейка всего вышеприведенного. Если вы боитесь что там в куки валится мусор - лучше проверять их. Это быстрее, дешевле и проще интерпретировать. Если боитесь что в разных ситуациях в базу пишутся разные вещи - улучшайте проверки в существующих тестах, сценарий тут не сильно поможет.
Собственно это я и имею ввиду утверждая, что автоматические тесты лучше дизайнить отдельно. Оправдание паранойи развесистыми сценарными тестами это очень дорогостоящее удовольствие. Иногда необходимое, но зачастую служащее как оправдание того, что кому-то лень заниматься Failure Model.

ЗЫ: А про Acceptance Testing есть старенькая и очень хорошая презентация от Болтона, кстати. В случае с автоматизацией ко всем бедам можно просто пририсовать, что приемочный тест будучи автоматизированным тупеет на глазах. Тем самым используя, например, всякие BDD фреймы (да и просто большие наборы приемочных тестов) стоит очень хорошо понимать с чем связались.
  • 0


Количество пользователей, читающих эту тему: 0

0 пользователей, 0 гостей, 0 анонимных