В гонитві за якістю коду: Тестування продуктивності за допомогою JUnitPerf (исходники), Різне, Програмування, статті

Тестування продуктивності в процесі розробки додатків зазвичай відкладається на останній момент, і не тому, що воно не є важливим, а тому, що досить складно виконати ефективне тестування з багатьма невідомими змінними. У цьому місяці Ендрю Гловер в серії “В гонитві за якістю” розгляне приклад тестування продуктивності в складі процесу розробки і покаже два простих способи тестування.


При розробці додатків перевірка продуктивності додатків практично завжди залишається на другому плані. Зверніть увагу – перевірка продуктивності додатків. Продуктивність програми завжди залишається головною складовою, а перевірка рідко включається в цикл розробки.


Тестування продуктивності зазвичай відкладається на кінцеві стадії розробки з різних причин. З мого досвіду, підприємства не включають в процес розробки тестування продуктивності, оскільки не знають, що очікувати від програми в процесі розробки. Кількісні показники відкидаються, а припущення робляться на основі очікуваної завантаження.


Як правило, тестування продуктивності виходить на передній план після одного з таких подій:



У цьому місяці будуть представлені два простих способи тестування продуктивності, що застосовуються до виникнення вищевказаних ситуацій.


Тестування за допомогою JUnitPerf


Дізнатися базові низькорівневі показники продуктивності на початкових стадіях розробки програмного забезпечення можна просто за допомогою JUnit. Середа JUnitPerf дозволяє швидко виконувати тести з простою навантаженням і навіть виконувати тестування з навантаженням.


За допомогою JUnitPerf можна створити два типи тестування: TimedTest і LoadTest. Обидва типи засновані на шаблоні проектування Decorator і використовують механізм suite середовища JUnit. TimedTest створює межа верхнього рівня для тестування, якщо межа перевищується, тест вважається невдалим. LoadTest діє спільно з таймерами і створює штучну навантаження для окремого тесту за допомогою його виконання потрібну кількість разів з інтервалами, що задаються таймером.


Відповідні тести з синхронізацією


JUnitPerf TimedTest дозволяє створювати тести із зв’язаним порогом часу. При перевищенні порога тест вважається невдалим (навіть якщо логіка тестування виконується успішно). Серед іншого, тести з синхронізацією корисно використовувати для з’ясування та контролю показників продуктивності для важливих бізнес-методів. Можна навіть створювати більш детальні тести і тестувати ряд методів для забезпечення їх відповідності певному тимчасовому порогу.


Наприклад, уявімо додаток з елементами для введення даних, в якому деякі важливі бізнес-методи, наприклад, метод createWidget(), Строго залежать від порогів продуктивності. Ймовірно, буде потрібно виконати тестування продуктивності функціонального аспекту виконання методу create(). Як правило, це з’ясовується на останніх етапах розробки різними групами за допомогою різних інструментів, які зазвичай не містять методів точного визначення. Припустимо, замість цього вирішено спробувати методологію раннього і частого тестування.


Створення TimedTest починається зі звичайного тестування JUnit. Іншими словами TestCase або його похідна доповнюється, створюється метод, що починається з test (Див. лістинг 1):


Лістинг 1. Просте тестування графічного елементу інтерфейсу




public class WidgetDAOImplTest extends TestCase {
private WidgetDAO dao;
public void testCreate() throws Exception{
IWidget wdgt = new Widget();
wdgt.setWidgetId(1000);
wdgt.setPartNumber(“12-34-BBD”);
try{
this.dao.createWidget(wdgt);
}catch(CreateException e){
TestCase.fail(“CreateException thrown creating a Widget”);
}
}
protected void setUp() throws Exception {
ApplicationContext context =
new ClassPathXmlApplicationContext(“spring-config.xml”);
this.dao = (WidgetDAO) context.getBean(“widgetDAO”);
}
}

Оскільки JUnitPerf являє собою середу на основі Decorator, для її фактичного використання необхідно надати метод suite() і додати до існуючого тестування TimedTest. Для TimedTest використовуються ті ж параметри, що й для Test, А також такий же інтервал часу для виконання тесту.


Також є можливість передати прапор boolean в якості третьої аргументу (false), Який приводить до швидкого невдалому завершенні тестування, тобто, якщо перевищено максимально допустимий час, JUnitPerf негайно вважає тестування невдалим. В іншому випадку тестування виконується до повного завершення і визнається як невдалий. Різниця досить тонке: виконання тестування без додаткового прапора дозволяє оцінити загальний час, навіть в разі невдалого тесту. Передача значення false, Однак, означає, що загальний час виконання надаватися не буде.


Наприклад, в лістингу 2 виконується метод testCreate() з двосекундних стелею. Якщо під час виконання загальний час перевищить це значення, тестування вважається невдалим. Додатковий параметр boolean не передається, тому тестування виконується повністю, як довго б воно не тривало.


Лістинг 2. Метод suite, реалізований для створення TimedTest




public static Test suite() {
long maxElapsedTime = 2000; //2 seconds
Test timedTest = new TimedTest(
new WidgetDAOImplTest(“testCreate”), maxElapsedTime);
return timedTest;
}

Дане тестування зазвичай виконується в середовищі JUnit, що існують завдання Ant, претенденти Eclipse і т.д запускають це тестування, як і будь-який інший тест JUnit. Єдина відмінність полягає в тому, що дане тестування виконується в контексті таймера.


Зайве тестування з навантаженням


На противагу перевірки тимчасового порогу для методу (або ряду методів) в сценарії тестування в JUnitPerf використовується тестування з навантаженням. Як і при TimedTest, Тестування LoadTest середовища JUnitPerf “s діє як decorator, включаючи JUnit Test з додатковою потокової інформацією для моделювання навантаження.


За допомогою LoadTest можна задати кількість імітіруемих користувачів (тобто потоків) і навіть забезпечити механізм синхронізації для запуску потоків. В JUnitPerf є два типи Timer: ConstantTimer і RandomTimer. Надаючи обидва ці типи для LoadTest, Можна більш реалістично змоделювати користувача навантаження. Без Timer всі потоки запускаються одночасно.


У лістингу 3 представлено тестування з навантаженням для 10 модельованих користувачів, реалізоване за допомогою ConstantTimer:


Лістинг 3. Реалізація методу suite для створення тестування з навантаженням




public static Test suite() {
int users = 10;
Timer timer = new ConstantTimer(100);
return new LoadTest(
new WidgetDAOImplTest(“testCreate”),
users, timer);
}

Зверніть увагу, що метод testCreate() запускається 10 разів, кожен потік запускається з затримкою в 100 мілісекунд. Порогових значень не задано. Ці методи просто виконуються до кінця, у разі збою виконання JUnit створює відповідний звіт про помилку.


Додавання стилю


Шаблони Decorator не обмежуються простим додаванням. Наприклад, в Java ™ у введення / висновок можна додати FileInputStream з InputStreamReader з BufferedReader (Просто запам’ятайте це: BufferedReader in = new BufferedReader(new InputStreamReader(new FileInputStream(“infilename”), “UTF8”))).


Декорування можна виконувати на декількох рівнях і з класами TimedTest і LoadTest JUnitPerf. Якщо два класи декорують один одного, це призводить до деяких непереборною сценаріями тестування, наприклад, сценарій, в якому навантаження розміщується в бізнес-прикладі, а також застосовується тимчасової поріг. Або можна об’єднати два попередніх сценарію тестування:



У лістингу 4 показано, що станеться, якщо застосувати зазначені вище специфікації до декорування нормального Test методом LoadTest, Який декорується TimedTest:


Лістинг 4. Тестування з синхронізацією і декорованої навантаженням




public static Test suite() {
int users = 10;
Timer timer = new ConstantTimer(100);
long maxElapsedTime = 2000;
return new TimedTest(new LoadTest(
new WidgetDAOImplTest(“testCreate”), users, timer),
maxElapsedTime);
}

Як видно, метод testCreate() виконується 10 раз (кожен потік запускається із затримкою 100 мілісекунд), кожен потік повинен завершуватися в інтервалі двох секунд, інакше виконання сценарію тестування буде вважатися неуспішним.


Хай буде покупець обачний


Хоча JUnitPerf являє собою середовище тестування продуктивності, що задаються значення повинні задаватися з урахуванням приблизних оцінок. Поскільки всі тести, декоруємі JUnitPerf, виконуються в середовищі JUnit, додається службова інформація, особливо при застосуванні фіксації. Оскільки JUnit декорує всі тести setUp і методом tearDown(), Необхідно враховувати час виконання в загальному контексті сценарію тестування.


Відповідно, я часто створюю тести, які використовують необхідну логіку фіксації, а також виконую контрольне тестування для визначення базових значень. Це приблизна оцінка, але вона служить як бази, яку потрібно додавати до будь пороговому значенню в тесті.


Наприклад, якщо виконання контрольного тестування, декорованого логікою фіксації, що використовує DbUnit, займає 2,5 секунди, то до всіх необхідним пороговим значенням JUnitPerf необхідно додати це час. Визначити контрольний час можна за допомогою еталонного тесту, аналогічного представленому в лістингу 5:


Лістинг 5. Еталонне тестування для JUnitPerf




public class DBUnitSetUpBenchmarkTest extends DatabaseTestCase {
private WidgetDAO dao = null;
public void testNothing(){
//should be about 2.5 seconds
}
protected IDatabaseConnection getConnection() throws Exception {
Class driverClass = Class.forName(“org.hsqldb.jdbcDriver”);
Connection jdbcConnection =
DriverManager.getConnection(
“jdbc:hsqldb:hsql://127.0.0.1”, “sa”, “);
return new DatabaseConnection(jdbcConnection);
}
protected IDataSet getDataSet() throws Exception {
return new FlatXmlDataSet(new File(“test/conf/seed.xml”));
}
protected void setUp() throws Exception {
super.setUp();
final ApplicationContext context =
new ClassPathXmlApplicationContext(“spring-config.xml”);
this.dao = (WidgetDAO) context.getBean(“widgetDAO”);
}
}

Зверніть увагу, що метод testNothing() в лістингу 5 не виконує нічого. Його призначення полягає у визначенні загального часу виконання методу setUp() (Яке задається в базі даних за допомогою DbUnit).


Також слід пам’ятати, що час тестування змінюється в залежності від конфігурації комп’ютера і програм, що виконуються в момент запуску тестування JUnitPerf. Я вважаю, що виділення тестів JUnitPerf в окрему категорію дозволяє відокремити їх від звичайних тестувань. Це означає, що вони не виконуються при кожному запуску тестування, як, наприклад, перевірка коду в середовищі CI. Я також зазвичай створюю завдання Ant для запуску цих тестувань тільки під час постановочних сценаріїв або в середовищах, де враховується тестування продуктивності.


Просто спробуйте!


Тестування продуктивності за допомогою JUnitPerf ні в якому разі не є точною наукою, але це чудовий спосіб визначення і контролю продуктивності коду програми на низькому рівні на ранніх стадіях розробки. До того ж ця розширена середу JUnit на основі шаблону Decorator дозволяє використовувати JUnitPerf для декорування існуючих тестувань JUnit.


Тільки подумайте про час, витрачений на занепокоєння про те, як додаток буде працювати з навантаженням. Тестування продуктивності за допомогою JUnitPerf являє собою один із способів заощадити час на більш важливі речі, при цьому також забезпечується якість коду програми.

Схожі статті:


Сподобалася стаття? Ви можете залишити відгук або підписатися на RSS , щоб автоматично отримувати інформацію про нові статтях.

Коментарів поки що немає.

Ваш отзыв

Поділ на параграфи відбувається автоматично, адреса електронної пошти ніколи не буде опублікований, допустимий HTML: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

*

*