Учебное пособие по JUnit4 + практика

модульный тест
1. Что такое JUnit?

JUnit — это среда модульного тестирования для языка программирования Java для написания и повторного запуска автоматических тестов.

Во-вторых, функции JUnit:
  • JUnit — это открытая среда ресурсов для написания и запуска тестов.
  • Предоставляет аннотации для идентификации методов тестирования.
  • Предоставьте утверждения для проверки ожидаемых результатов.
  • JUnit Test позволяет писать код быстрее и улучшать качество.
  • JUnit элегантен и лаконичен. Менее сложно и требует меньше времени.
  • Тесты JUnit могут запускаться автоматически, проверять свои собственные результаты и предоставлять немедленную обратную связь. Таким образом, нет необходимости вручную просматривать отчеты о результатах испытаний.
  • Тесты JUnit могут быть организованы в наборы тестов, содержащие наборы тестов и даже другие наборы тестов.
  • JUnit отображает прогресс в виде полосы. Зеленый, если работает хорошо, красный, если не работает.
3. Аннотации JUnit
аннотация описывать
@Test Тестовая аннотация, обозначающая метод, может использоваться в качестве тестового примера.
@Before Аннотация «До» указывает, что метод должен выполняться перед каждым тестом в классе, чтобы выполнить определенные необходимые предварительные условия.
@BeforeClass В аннотации BeforeClass указано, что это статический метод, прикрепленный к классу, который должен выполняться один раз и перед всеми тестами класса.Эта ситуация обычно используется для тестовых расчетов, общих методов настройки (таких как подключения к базе данных).
@After В аннотации After говорится, что метод выполняется после каждого теста (например, сброса некоторых переменных, удаления временных переменных и т. д.) после выполнения каждого теста.
@AfterClass Когда все тесты необходимо выполнить после класса тестового примера JUnit, аннотацию AlterClass можно использовать для очистки некоторых ресурсов (например, соединений с базой данных).Примечание: метод должен быть статическим.
@Ignore Если вы хотите временно отключить выполнение определенного теста, вы можете использовать эту аннотацию, каждый метод аннотируется, поскольку @Ignore больше не будет выполняться.
@Runwith @Runwith помещается перед именем тестового класса, чтобы определить, как работает класс. Вы также можете оставить его неотмеченным, и будет использоваться бегун по умолчанию.
@Parameters Для использования параметризованных функций.
@SuiteClasses для комплексного тестирования
В-четвертых, утверждение JUnit
утверждение описывать
void assertEquals([String message],expected value,actual value) Утверждение, что два значения равны. Тип значения может быть int, short, long, byte, char, Object, первый параметр — необязательное строковое сообщение.
void assertTrue([String message],boolean condition) В результате условия
void assertFalse([String message],boolean condition) Утверждают, что условие ложно
void assertNotNull([String message],java.lang.Object object) Утверждают, что объект не является нулевым (null)
void assertNull([String message],java.lang.Object object) Утверждают, что объект пуст (null)
void assertSame([String message],java.lang.Object expected,java.lang.Object actual) Утверждают, что два объекта ссылаются на один и тот же объект
void assertNotSame([String message],java.lang.Object unexpected,java.lang.Object actual) Утверждает, что два объекта не относятся к одному и тому же объекту
void assertArrayEquals([String message],expectedArray,resultArray) Утверждают, что ожидаемый массив и результирующий массив равны, типы массивов могут быть int, short, long, byte, char, Object

Давайте посмотрим на пример использования утверждений. УтверждениеTest.java

public class AssertionTest {

    @Test
    public void test() {
        String obj1 = "junit";
        String obj2 = "junit";
        String obj3 = "test";
        String obj4 = "test";
        String obj5 = null;
        
        int var1 = 1;
        int var2 = 2;

        int[] array1 = {1, 2, 3};
        int[] array2 = {1, 2, 3};

        Assert.assertEquals(obj1, obj2);

        Assert.assertSame(obj3, obj4);
        Assert.assertNotSame(obj2, obj4);
        
        Assert.assertNotNull(obj1);
        Assert.assertNull(obj5);

        Assert.assertTrue(var1 < var2);
        Assert.assertFalse(var1 > var2);

        Assert.assertArrayEquals(array1, array2);

    }
}

Как мы видим в приведенном выше классе, эти методы утверждений работают.

  • assertEquals() Если два сравниваемых объекта равны, этот метод завершится нормально, в противном случае в окне JUnit отобразится ошибка, и тест прервется.
  • Методы assertSame() и assertNotSame() проверяют, что две ссылки на объекты указывают на один и тот же объект.
  • Методы assertNull() и assertNotNull() проверяют, является ли переменная нулевой или не нулевой (null).
  • Методы assertTrue() и assertFalse() проверяют, являются ли условия или переменные истинными или ложными.
  • assertArrayEquals() сравнивает два массива, если они равны, то метод продолжает работу. Об ошибке не сообщается. В противном случае сбой будет отображаться в окне JUnit и прервать тест.
Пять, процесс выполнения JUnit

JuntiTest.java

public class JunitTest {

    @BeforeClass
    public static void beforeClass() {
        System.out.println("in before class");
    }

    @AfterClass
    public static void afterClass() {
        System.out.println("in after class");
    }

    @Before
    public void before() {
        System.out.println("in before");
    }

    @After
    public void after() {
        System.out.println("in after");
    }

    @Test
    public void testCase1() {
        System.out.println("in test case 1");
    }

    @Test
    public void testCase2() {
        System.out.println("in test case 2");
    }

}

После выполнения всего тестового класса через идею результат выполнения:

in before class
in before
in test case 1
in after
in before
in test case 2
in after
in after class
6. Игнорировать тест
  • Метод тестирования, помеченный @Ignore, не будет выполнен.
  • Если тестовый класс помечен @Ignore, его тестовые методы не будут выполняться.

Мы только что пометили метод testCase2() в тестовом классе как @Ignore,

    @Ignore
    @Test
    public void testCase2() {
        System.out.println("in test case 2");
    }

Затем этот метод игнорируется при выполнении тестового класса, и результат:

in before class
in before
in test case 1
in after

Test ignored.
in after class
7. Проверка временем

JUnit предоставляет удобную опцию для приостановки. Если тестовый пример занимает больше времени, чем указанное количество миллисекунд, JUnit автоматически помечает его как не пройденный. Параметр timeout используется с аннотацией @Test, например @Test(timeout =1000 ). Продолжайте использовать предыдущий пример, теперь увеличьте время выполнения testCase1 до 5000 миллисекунд, добавьте параметр времени, установите время ожидания на 1000 миллисекунд, а затем выполните тестовый класс.

    @Test(timeout = 1000)
    public void testCase1() throws InterruptedException {
        TimeUnit.SECONDS.sleep(5000);
        System.out.println("in test case 1");
    }

testCase1 помечен как не пройденный и выброшено исключение, результат выполнения:

in before class
in before
in after

org.junit.runners.model.TestTimedOutException: test timed out after 1000 milliseconds

	at java.lang.Thread.sleep(Native Method)
	at java.lang.Thread.sleep(Thread.java:340)
	at java.util.concurrent.TimeUnit.sleep(TimeUnit.java:386)
	at com.lxs.JUnit.JunitTest.testCase1(JunitTest.java:35)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
	at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
	at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
	at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
	at org.junit.internal.runners.statements.FailOnTimeout$CallableStatement.call(FailOnTimeout.java:298)
	at org.junit.internal.runners.statements.FailOnTimeout$CallableStatement.call(FailOnTimeout.java:292)
	at java.util.concurrent.FutureTask.run(FutureTask.java:266)
	at java.lang.Thread.run(Thread.java:748)

in before
in test case 2
in after
in after class
Восемь, ненормальный тест

Junit предоставляет возможность отслеживать исключения с помощью обработки кода. Вы можете протестировать код, если он выдает желаемое исключение. Ожидаемый параметр используется с аннотацией @Test. Теперь давайте посмотрим на @Test(ожидаемый). Создайте новый тестовый метод testCase3().

    @Test(expected = ArithmeticException.class)
    public void testCase3() {
        System.out.println("in test case 3");
        int a = 0;
        int b = 1 / a;
    }

Выполните только метод testCase3(), потому что получено ожидаемое исключение, тест пройден, и результат

in before class
in before
in test case 3
in after
in after class

Если вы не получили ожидаемое исключение:

in before class
in before
in test case 3
in after

java.lang.AssertionError: Expected exception: java.lang.ArithmeticException

in after class
9. Параметрический тест

Junit 4 представляет новый функциональный параметризованный тест. Параметризованные тесты позволяют разработчикам запускать один и тот же тест снова и снова с разными значениями. Вы выполните 5 шагов, чтобы создать параметризованный тест:

- Укажите специальный раннер org.junit.runners.Parameterized для тестовых классов, которые готовы использовать параметризованные тесты.

  • Объявите несколько переменных для тестового класса, которые используются для хранения ожидаемого значения и данных, используемых для теста.
  • Объявите публичный конструктор с параметрами для тестового класса и присвойте в нем значения нескольким переменным, объявленным на втором проходе.
  • Объявите общедоступный статический метод для тестового класса, аннотированный org.junit.runners.Parameterized.Parameters и возвращающий java.util.Collection , и инициализируйте все пары параметров, которые необходимо протестировать в этом методе.
  • Напишите тестовый метод, который использует определенные переменные в качестве параметров для тестирования.
Что такое @RunWith?

Прежде всего, мы должны различать несколько понятий: тестовые методы, тестовые классы, тестовые наборы и прогонщики тестов.

  • Методы тестирования — это некоторые функции, аннотированные с помощью @Test.
  • Тестовый класс — это файл **Test.java, содержащий один или несколько тестовых методов,
  • Набор тестов — это набор, который может содержать несколько тестовых классов.
  • Тестовый бегун определяет предпочтительный способ запуска этих тестовых люков / классов / методов.

И @Runwith помещается перед именем тестового класса, чтобы определить, как класс работает. Вы также можете оставить его неотмеченным, и будет использоваться бегун по умолчанию. Обычные бегуны:

  • @RunWith(Parameterized.class) Параметризованный бегун, использующий функцию параметризации JUnit с @Parameters
  • @RunWith(Suite.class) @SuiteClasses({ATest.class,BTest.class,CTest.class}) Средство запуска набора тестов работает с функцией набора тестов.
  • @RunWith(JUnit4.class), бегун по умолчанию для junit4
  • @RunWith(JUnit38ClassRunner.class) для бегунов, совместимых с junit3.8
  • Другие бегуны с дополнительными функциями. Например @runwith (SpringJunit4Classrunner.Class) объединяет ряд функций пружины

PrimeNumberCheckerTest.java

/**
 * 步骤一: 指定定参数运行器
 */
@RunWith(Parameterized.class)
public class PrimeNumberCheckerTest {

    /**
     * 步骤二:声明变量
     */
    private Integer inputNumber;
    private Boolean expectedResult;
    private PrimeNumberChecker primeNumberChecker;

    /**
     * 步骤三:为测试类声明一个带有参数的公共构造函数,为变量赋值
     */
    public PrimeNumberCheckerTest(Integer inputNumber,
                                  Boolean expectedResult) {
        this.inputNumber = inputNumber;
        this.expectedResult = expectedResult;
    }

    /**
     * 步骤四:为测试类声明一个使用注解 org.junit.runners.Parameterized.Parameters 修饰的,返回值为
     * java.util.Collection 的公共静态方法,并在此方法中初始化所有需要测试的参数对
     *   1)该方法必须由Parameters注解修饰 
          2)该方法必须为public static的 
          3)该方法必须返回Collection类型 
          4)该方法的名字不做要求 
          5)该方法没有参数 
     */
    @Parameterized.Parameters
    public static Collection primeNumbers() {
        return Arrays.asList(new Object[][]{
                {2, true},
                {6, false},
                {19, true},
                {22, false},
                {23, true}
        });
    }

    @Before
    public void initialize() {
        primeNumberChecker = new PrimeNumberChecker();
    }

    /**
     * 步骤五:编写测试方法,使用自定义变量进行测试
     */
    @Test
    public void testPrimeNumberChecker() {
        System.out.println("Parameterized Number is : " + inputNumber);
        Assert.assertEquals(expectedResult,
                primeNumberChecker.validate(inputNumber));
    }
}

PrimeNumberChecker.java

public class PrimeNumberChecker {

    public Boolean validate(final Integer parimeNumber) {
        for (int i = 2; i < (parimeNumber / 2); i++) {
            if (parimeNumber % i == 0) {
                return false;
            }
        }
        return true;
    }
}

JUnit будет выполняться несколько раз в соответствии с заданными параметрами и результатом выполнения:

Parameterized Number is : 2
Parameterized Number is : 6
Parameterized Number is : 19
Parameterized Number is : 22
Parameterized Number is : 23
10. Набор тестов

«Комплексное тестирование» означает объединение нескольких тестовых случаев и их запуск. В JUnit аннотации @RunWith и @Suite используются для запуска наборных тестов. Давайте сначала создадим несколько тестовых классов

public class JunitTest1 {

    @Test
    public void printMessage(){
        System.out.println("in JunitTest1");
    }
}
public class JunitTest2 {

    @Test
    public void printMessage(){
        System.out.println("in JunitTest2");
    }
}
@RunWith(Suite.class)
@Suite.SuiteClasses({
        /**
         * 此处类的配置顺序会影响执行顺序
         */
        JunitTest1.class,
        JunitTest2.class
})
public class JunitSuite {

}

Выполните тестовый класс JunitSuite, результат выполнения:

in JunitTest1
in JunitTest2