субота, 18 квітня 2015 р.

JUnit 4.x: основи роботи

     JUnit - це звичайний фреймворк, який призначений для написання та запуску тестових програм. Тобто це набір класів (jar-пакет), які ми використовуємо для створення інших, тестових джава-класів, які будуть перевіряти коректність роботи цільових класів. Фреймворк не пише тести замість вас, їх потрібно кодувати в Java, як і звичайні класи. Тільки запускати тест на виконання потрібно з допомогою JUnit-ранерів (test runner).

     Офіційний сайт проекту - junit.org. , в розділі  FAQ якого можна почитати про основи роботи з фреймворком. З цього сайту потрібно завантажити на комп'ютер jar-пакети: junit.jar та hamcrest-core.jar. Потім записати шлях до них в системну змінну CLASSPATH.


     В 4-й версії фреймворку є багато нововведень. Тепер робота тестового модуля керується за допомогою анотацій (annotations).

     Тест - це звичайний джава-клас, який складається із полів та методів. Методи, які марковані анотацією @Test, викликають методи цільового класу, відправляючи їм наперед відомі аргументи та перевіряючи отриманий результат із очікуваним.

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

      Відповідно до принципу програмування test-driven development, писати тести потрібно ще до написання самого коду програми. Потрібно знати, який результат має повернути майбутній метод, якщо його викликати із відомим набором аргументів. Наприклад, нам потрібно написати клас ArithmeticOperations, який буде мати чотири методи для виконання арифметичних дій над цілими числами: додати (add), відняти (subtract), помножити (multiply), розділити (divide). Очевидно, що якщо 100 + 100, то маємо отримати 200. Якщо 100 - 100, то маємо отримати нуль. Якщо щось помножити на нуль, то маємо отримати також нуль, якщо щось поділити на нуль, то ми повинні отримати помилку.

     Наступне питання, де зберігати тести? Один із методів - тримати тестові класи та цільові класи в одних і тих же пакетах, але фізично зберігати в паралельних директоріях та прописати CLASSPATH до обох локацій. В такому разі, тестовий клас буде мати доступ до всіх членів класу з публічним та пакетним доступами. А при компілюванні програми буде легше розділити байтфайли програми та тестів.

     Тестовий клас може мати наступний вигляд:

package arithmetic_operations;

import org.junit.*;
import static org.junit.Assert.*;

import static arithmetic_operations.ArithmeticOperations.*;



public class ArithmeticOperationsTest {
   
   private int int100;
   private int int0;
   
   
   @BeforeClass
   // run for one time before all test cases
   // for example - connecte to DB, open the file etc...
   public static void runBeforeClass() {
   
   }
   
   @AfterClass
   // run for one time after all test cases
   // for example - close DB connection, close the file etc...
   public static void runAfterClass() {
   
   } 
   
   
   @Before
   // will be executed before every test method
   public void setUp() {
    int100 = 100;
    int0 = 0;
   }
   
   @After
   // will be executed after every test method
   public void tearDown() {
    // nothing to code
   } 
   
   @Test
   // each test we annotate with Test annotation
   public void addTest() {
   assertEquals(200, add(int100, int100));
   }
   
   @Test
   // each test we annotate with Test annotation
   public void subtractTest() {
   assertEquals(int0, subtract(int100, int100));
   }
   
   @Test
   // each test we annotate with Test annotation
   public void multiplyTest() {
   assertTrue(multiply(int100, int0) == int0);
   }
   
   @Test(expected = ArithmeticException.class)
   // A test that passes when an expected exception is thrown.
   // ArithmeticException -> integer division by zero.
   public void divideByZeroTest() {
    divide(int100, int0);
   }
   
   @Test
   /*
    * Declare the exception in the throws clause 
    * of the test method and don't catch the exception 
    * within the test method. Uncaught exceptions 
    * will cause the test to fail with an error. 
    */
   public void divideByZeroExceptionTest()
   throws ArithmeticException {
    
    divide(int100, int0);
   }
   
   @Ignore("Not Finished")
   @Test
   public void divideTest() {
   
   } 
   
}

     Опишемо призначення використаних анотацій:

@BeforeClass - метод виконується один раз перед викликом всіх інших методів. В ньому можна, наприклад, встановити зв'язок з базою даних, відкрити файл, і т.п.

@AfterClass - метод виконується один раз в кінці програми. В ньому можна, наприклад, закрити зв'язок з базою даних, закрити файл, і т.п.

@Before  -  метод виконується перед кожним викликом тестового методу. В ньому зазвичай ініціалізуються значення так званих змінних test fixture.

@After - метод виконується після кожного виклику тестового методу.

@Test - цією анотацією повинен бути позначений кожен метод, який ви будете використовувати в якості тесту.

@Test(expected = ArithmeticException.class) - тест буде вважатись вдалим, якщо при його виконанні буде отримано очікувану помилку. Наприклад, у нашому випадку при діленні на нуль ми повинні отримати помилку класу ArithmeticException.

@Ignore("Not Finished") - тест не буде виконуватись. Наприклад, ми ще не закінчили написання тесту і не хочемо, щоб він виконувався. Текст в дужках може бути довільним, або бути відсутнім.

     Клас ArithmeticOperations виглядає наступним чином:

package arithmetic_operations;

public class ArithmeticOperations {
 
 public static int add(int a, int b)
 {
  return a+b;
 }
 
 public static int subtract(int a, int b)
 {
  return a-b;
 }
 
 public static int multiply(int a, int b)
 {
  return a*b;
 }

 public static int divide(int a, int b)
 {
  return a/b;
 }
}

     В тестах для перевірки результату виклику методу використовують допущення - assertions. Реалізовані вони у вигляді статичних методів, які знаходяться в класі org.junit.Assert. Найбільш поширені припущення:

 - void assertEquals(boolean expected, boolean actual)

void assertTrue(boolean condition)

void assertFalse(boolean condition)

- void assertNotNull(Object object)

- void assertNull(Object object) 

     Щоб запустити тест в Екліпсі, потрібно додати JUnit пакет до Java Build Path нашого проекту:



      Потім з контекстного меню редактора коду вибрати Run As -> JUnit Test :



В лівій панелі відкриється панель JUnit з повідомленнями про результат тестування:


 
Корисні посилання:
code.google.com
javarevisited.blogspot.ca  - 5 книжок по JUnit.
sqa.fyicenter.com
junit.sourceforge.net - сурс-код
csc.calpoly.edu
github.com
www.cavdar.net
javacodegeeks.com
stackoverflow.com

Немає коментарів:

Дописати коментар