Статьи

easyb: Представляем разговорные юнит-тесты для Java

[img_assist | nid = 836 | title = | desc = | link = none | align = right | width = 240 | height = 210] Эндрю Гловер является соавтором Groovy в действии и написал тестовую среду под названием easyb. Новая структура способствует более «разговорному» подходу к модульному тестированию.

Q: Привет, Эндрю, ты соавтор Groovy in Action и автор фреймворка easyb test . Что такое easyb?

A: easyb — это система проверки истории, построенная в духе разработки, основанной на поведении. Он написан в основном для Groovy и предназначен для работы с Groovy и Java. С easyb вы можете писать истории, которые помогают проверять приложения — например, a Stack. С помощью стеков вы можете выдвигать и выдвигать значения — pushметод должен помещать вещи в некоторую коллекцию, а popметод должен удалять их, верно? Используя easyb, вы можете создать историю, которая представляет собой серию сценариев, которые читаются как

учитывая некоторый контекст,
когда что-то происходит,
тогда должно произойти что-то еще

С этим форматом вы могли бы написать несколько сценариев, таких как «pop вызывается в стеке с одним значением» или «peek вызывается в стеке с одним значением» — тогда вы можете кодировать конкретный сценарий с помощью givens, whens и thens, например этот:

scenario "pop is called on stack with one value", {

given "an empty stack with foo", {
stack = new Stack()
stack.push("foo")
}

when "pop is called", {
popVal = stack.pop()
}

then "foo should be returned", {
popVal.shouldBe "foo"
}

and

then "the stack should be empty", {
stack.empty.shouldBe true
}
}

easyb также поддерживает гибкий синтаксис проверки — видите shouldBeвызов, который автоматически подключен ко всему в контексте сценария? Вы можете использовать shouldBeEqual, shouldBeEqualTo, shouldEqualи, конечно , негативы , которые так же, как shouldNotBeи т.д., и т.д.

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

История: в стеке
сценарий pop с одним значением вызывается с одним значением,
заданным пустым стеком с foo
при вызове pop,
затем должен быть возвращен foo,
тогда стек должен быть пустым

В: Easyb предназначен для модульного тестирования? Или его также можно использовать для интеграционного тестирования?

A: Да и Да! Это зависит только от вас, как вы используете его — из коробки, фреймворк поставляется с плагином, который поддерживает управление базой данных через DbUnit , так что есть много поддержки для интеграционного тестирования. Например, если вы обнаружите, что конкретная история требует определенных предварительных данных, вы можете поместить эти данные в базу данных с помощью database_modelвызова, который принимает стандартную информацию о соединении JDBC (URL, имя пользователя, драйвер и т. Д.), А затем Stringпредставляет стандарт DbUnit. FlatXmlDataSetтип. Так, например, в givenпредложении вы можете заполнить базу данных следующим образом:

given "the database is properly seeded", {
database_model("org.hsqldb.jdbcDriver",
"jdbc:hsqldb:hsql://127.0.0.1", "sa", ""){
return new File("./src/conf/seed.xml").text
}
}

Это облегчает интеграционное тестирование, не так ли? Плагин DbUnit представляет собой отдельный файл jar, который вы можете загрузить с веб-сайта easyb — просто убедитесь, что у вас есть этот jar в вашем classpath, и easyb найдет его, если вы вызовете database_modelвызов. Наша цель с плагинами состоит в том, чтобы иметь различные из них, которые облегчают тестирование более высокого уровня, поэтому возможно, что будет плагин Selenium.

Я склонен находить, что использование формата истории даже на объекте (то есть на уровне модульного тестирования) помогает управлять вещами в истинном стиле TTD — например, взять классический пример Money из примера JUnit Test Infected — учитывая addметод, вы Можно написать модульный тест (в JUnit) так:

public class MoneyTest extends TestCase {

public void testSimpleAdd() {
Money m12CHF= new Money(12, "CHF");
Money m14CHF= new Money(14, "CHF");
Money expected= new Money(26, "CHF");
Money result= m12CHF.add(m14CHF);
Assert.assertTrue(expected.equals(result));
}
}

Написание того же кода на easyb примерно так:

scenario "two moneys of the same currency are added", {

given "one money object is added to another", {
total = new Money(12, "CHF").add(new Money(14, "CHF"))
}

then "the total amount should be the sum of the two", {
total.amount().shouldBe 26
}

}

Обратите внимание, что в процессе написания простой истории я был вынужден думать о сценариях (до того, как набрал строку кода), и при этом я быстро обнаружил, что думаю о других сценариях — например, о двух Moneyобъектах разных валют. JUnit также не мешает вам так думать, но я считаю, что формат истории почти напрашивается заранее.

Q: Какие преимущества дает разработчикам easyb?

A: это легко! Серьезно, однако, easyb заставляет вас думать о поведении — о том, как все должно работать, а затем позволяет вам выразить эти ожидания естественным образом — order.getPrice().shouldBe "$56"вместо того assertи того и другого .

Истории также способствуют сотрудничеству — они представляют собой механизм, соединяющий развитие и заинтересованные стороны, во многом как предназначены Fit и Fitnesse. Плюс, easyb это весело! История DSL и структура ожиданий довольно забавны в использовании — вы также можете быстро связать ожидания, такие как

var.shouldNotBe null
and
var.length().shouldEqual 6

Отсутствие круглых скобок и использование пробелов делает это легко кодировать и легко читать.

В: Почему вы решили написать easyb на Groovy, а не на другом динамическом языке?

A: У Ruby уже есть RSpec, который является превосходной средой, и я хотел сделать нечто подобное доступным для мира Java — Groovy был для меня естественным выбором, так как я достаточно хорошо в этом разбираюсь. Не смотря на предвзятость, создание DSL в Groovy невероятно просто: мне также выпала роскошь кодировать первоначальный прототип с Venkat Subramaniam и Джеффом Брауном, которые являются удивительно талантливыми разработчиками Groovy.

Вопрос: По вашему мнению, способен ли easyb заменить обычные модули модульного тестирования, такие как JUnit или TestNG, в проектах разработки?

A: Вы, конечно, могли бы, если бы у вас были сильные чувства по этому поводу, но TestNG (и JUnit 4) имеют некоторые неотразимые особенности! Например, TestNG проводит феноменальное параметрическое тестирование и поддерживает параллельное тестирование, группы тестирования и т. Д. Это зрелые, хорошо продуманные фреймворки, которые предлагают некоторые замечательные функции, которые нельзя упускать из виду. Я все еще использую обе структуры, где это уместно, и призываю людей делать то же самое.

В: Есть ли интеграция с JUnit или TestNG, чтобы истории easyb стали частью наборов тестов и непрерывной интеграции?

A: На данный момент нет интеграции с JUnit или TestNG; тем не менее, вы, безусловно, можете запускать свои истории easyb через Ant (готовится плагин Maven) следующим образом:

<easyb failureProperty="easyb.failed">
<classpath>
<path refid="build.classpath" />

<pathelement path="target/classes" />
</classpath>

<report location="target/story.txt" format="txtstory" />

<behaviors dir="behavior">
<include name="**/*Story.groovy" />
</behaviors>
</easyb>

Таким образом, вы можете легко настроить процесс CI, который запускает истории easyb по расписанию или при изменении кода.

В: Есть ли в easyb интеграция с IDE?

A: Не в данный момент, к сожалению. Он запускается через класс Java, поэтому вы можете легко создать профиль в Eclipse для запуска историй.

Спасибо за отличное интервью, Андрей!