Руководство по JSpec

Руководство по JSpec

1. обзор

Среды выполнения тестов, такие какJUnit иTestNG, предоставляют некоторые базовые методы утверждения (assertTrue,assertNotNull и т. Д.).

Кроме того, существуют структуры утверждений, такие какHamcrest,AssertJ иTruth, которые предоставляют плавные и богатые методы утверждения с именами, которые обычно начинаются с“assertThat”.

JSpec is another framework that allows us to write fluent assertions closer to the way we write specifications in our natural language, хотя и немного иначе, чем в других фреймворках.

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

2. Maven Зависимости

Давайте импортируем зависимостьjavalite-common, которая содержит JSpec:


    org.javalite
    javalite-common
    1.4.13

Для последней версии проверьтеMaven Central repository.

3. Сравнение стилей утверждения

Вместо типичного способа утверждения, основанного на правилах, мы просто пишем спецификацию поведения. Давайте посмотрим на быстрый пример утверждения равенства в JUnit, AssertJ и JSpec.

В JUnit мы бы написали:

assertEquals(1 + 1, 2);

А в AssertJ мы напишем:

assertThat(1 + 1).isEqualTo(2);

Вот как мы напишем тот же тест в JSpec:

$(1 + 1).shouldEqual(2);

JSpec использует тот же стиль, что и фреймворки fluent assertion, но опускает ведущее ключевое словоassert /assertThat и вместо него используетshould.

Написание утверждений таким образом делает егоeasier to represent the real specifications, продвигая концепции TDD и BDD.

Посмотрите, как этот пример очень близок к нашему естественному написанию спецификаций:

String message = "Welcome to JSpec demo";
the(message).shouldNotBe("empty");
the(message).shouldContain("JSpec");

4. Структура спецификаций

The specification statement consists of two parts: создатель ожиданий и метод ожидания.

4.1. Создатель ожиданий

Создатель ожиданияgenerates an Expectation object, использующий один из этих статически импортированных методов:a(),the(),it(),$():

$(1 + 2).shouldEqual(3);
a(1 + 2).shouldEqual(3);
the(1 + 2).shouldEqual(3);
it(1 + 2).shouldEqual(3);

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

Единственное отличие состоит в том, чтоthe it() method is type-safe позволяет сравнивать только объекты одного типа:

it(1 + 2).shouldEqual("3");

Сравнение объектов разных типов с использованиемit() приведет к ошибке компиляции.

4.2. Метод ожидания

Вторая часть описания спецификации - это метод ожидания, которыйtells about the required specification похож наshouldEqual,shouldContain.

Когда тест не проходит, исключение типаjavalite.test.jspec.TestException отображает выразительное сообщение. Мы увидим примеры таких сообщений об ошибках в следующих разделах.

5. Встроенные ожидания

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

5.1. Ожидание равенства

shouldEqual (), shouldBeEqual (), shouldNotBeEqual ()

Они указывают, что два объекта должны / не должны быть равны, с использованием методаjava.lang.Object.equals() для проверки равенства:

$(1 + 2).shouldEqual(3);

Сценарий сбоя:

$(1 + 2).shouldEqual(4);

выдаст следующее сообщение:

Test object:java.lang.Integer == (3)
and expected java.lang.Integer == (4)
are not equal, but they should be.

5.2. Логическое ожидание свойства

shouldHave (), shouldNotHave ()

Мы используем эти методы для указанияwhether a named boolean property of the object should/shouldn’t return true:

Cage cage = new Cage();
cage.put(tomCat, boltDog);
the(cage).shouldHave("animals");

Это требует, чтобы классCage содержал метод с подписью:

boolean hasAnimals() {...}

Сценарий сбоя:

the(cage).shouldNotHave("animals");

выдаст следующее сообщение:

Method: hasAnimals should return false, but returned true

shouldBe (), shouldNotBe ()

Мы используем их, чтобы указать, что тестируемый объект должен / не должен быть чем-то:

the(cage).shouldNotBe("empty");

Это требует, чтобы классCage содержал метод с сигнатурой“boolean isEmpty()”.

Сценарий сбоя:

the(cage).shouldBe("empty");

выдаст следующее сообщение:

Method: isEmpty should return true, but returned false

5.3. Тип Ожидание

shouldBeType (), shouldBeA ()

Мы можем использовать эти методы, чтобы указать, что объект должен быть определенного типа:

cage.put(boltDog);
Animal releasedAnimal = cage.release(boltDog);
the(releasedAnimal).shouldBeA(Dog.class);

Сценарий сбоя:

the(releasedAnimal).shouldBeA(Cat.class);

выдаст следующее сообщение:

class com.example.jspec.Dog is not class com.example.jspec.Cat

5.4. Ожидание отмены

shouldBeNull (), shouldNotBeNull ()

Мы используем их, чтобы указать, что тестируемый объект должен / не должен бытьnull:

cage.put(boltDog);
Animal releasedAnimal = cage.release(dogY);
the(releasedAnimal).shouldBeNull();

Сценарий сбоя:

the(releasedAnimal).shouldNotBeNull();

выдаст следующее сообщение:

Object is null, while it is not expected

5.5. Ссылочные ожидания

shouldBeTheSameAs (), shouldNotBeTheSameAs ()

Эти методы используются, чтобы указать, что ссылка на объект должна быть такой же, как и ожидаемая:

Dog firstDog = new Dog("Rex");
Dog secondDog = new Dog("Rex");
$(firstDog).shouldEqual(secondDog);
$(firstDog).shouldNotBeTheSameAs(secondDog);

Сценарий сбоя:

$(firstDog).shouldBeTheSameAs(secondDog);

выдаст следующее сообщение:

references are not the same, but they should be

5.6. Ожидание коллекции и содержимого строки

shouldContain(), shouldNotContain() Мы используем их, чтобы указать, что тестируемыеCollection илиMap должны / не должны содержать данный элемент:

cage.put(tomCat, felixCat);
the(cage.getAnimals()).shouldContain(tomCat);
the(cage.getAnimals()).shouldNotContain(boltDog);

Сценарий сбоя:

the(animals).shouldContain(boltDog);

выдаст следующее сообщение:

tested value does not contain expected value: Dog [name=Bolt]

Мы также можем использовать эти методы, чтобы указать, чтоString должен / не должен содержать данную подстроку:

$("Welcome to JSpec demo").shouldContain("JSpec");

И хотя это может показаться странным, мы можем распространить это поведение на другие типы объектов, которые сравниваются с помощью их методовtoString():

cage.put(tomCat, felixCat);
the(cage).shouldContain(tomCat);
the(cage).shouldNotContain(boltDog);

Чтобы уточнить, методtoString() объектаCattomCat выдаст:

Cat [name=Tom]

которая является подстрокой выводаtoString() объектаcage:

Cage [animals=[Cat [name=Tom], Cat[name=Felix]]]

6. Индивидуальные ожидания

В дополнение к встроенным ожиданиям, JSpec позволяет нам писать собственные ожидания.

6.1. Ожидание разницы

Мы можем написатьDifferenceExpectation, чтобы указать, что возвращаемое значение выполнения некоторого кода не должно быть равно определенному значению.

В этом простом примере мы убеждаемся, что операция (2 + 3) не даст нам результата (4):

expect(new DifferenceExpectation(4) {
    @Override
    public Integer exec() {
        return 2 + 3;
    }
});

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

Например, при выпуске животного изCage, содержащего двух животных, размер должен быть другим:

cage.put(tomCat, boltDog);
expect(new DifferenceExpectation(cage.size()) {
    @Override
    public Integer exec() {
        cage.release(tomCat);
        return cage.size();
    }
});

Сценарий сбоя:

Здесь мы пытаемся освободить животное, которого нет внутриCage:

cage.release(felixCat);

Размер не изменится, и мы получим следующее сообщение:

Objects: '2' and '2' are equal, but they should not be

6.2. Исключение Ожидание

Мы можем написатьExceptionExpectation, чтобы указать, что тестируемый код должен выдаватьException.

Мы просто передадим в конструктор ожидаемый тип исключения и предоставим его как универсальный тип:

expect(new ExceptionExpectation(ArithmeticException.class) {
    @Override
    public void exec() throws ArithmeticException {
        System.out.println(1 / 0);
    }
});

Сценарий отказа №1:

System.out.println(1 / 1);

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

Expected exception: class java.lang.ArithmeticException, but instead got nothing

Сценарий отказа № 2:

Integer.parseInt("x");

Это приведет к исключению, отличному от ожидаемого исключения:

class java.lang.ArithmeticException,
but instead got: java.lang.NumberFormatException: For input string: "x"

7. Заключение

Другие свободно распространяемые платформы утверждений предоставляют более совершенные методы для утверждений коллекций, утверждений об исключениях и интеграции Java 8, но JSpec предоставляет уникальный способ написания утверждений в форме спецификаций.

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

Полный исходный код для всех этих примеров можно найтиover on GitHub - в пакетеcom.example.jspec.