- Любое число, кратное 3, должно возвращать строку «Fizz»
- Любое число, кратное 5, должно возвращать строку «Buzz»
- Любое число, делимое на 3 и 5, должно возвращать строку «FizzBuzz»
- В противном случае номер должен быть возвращен в виде строки
Для сравнения я также включил для этого пример теста Java JUnit . Фактический код реализации (включенный здесь) для этого тривиален (частично из-за замысла), поскольку он просто показывает иллюстрацию используемых библиотек.
Для этого я использовал Eclipse v3.7.2 в Windows 7 с плагином Scala IDE v2.0.1.v-2_09 и Scala версии 2.9.0.1.
- Метафрейм для написания модульных и приемочных тестов по спецификации. Поддерживает одновременное выполнение, макетирование, создание отчетов, поддержку масштабируемости и скалярной проверки, тестирование на основе данных и тестирование спецификаций на основе форм. Проект возник из оригинальной (и в настоящее время устаревшей) среды тестирования BDD Scala Specs .
Ссылка на сайт
http://etorreborre.github.com/specs2/
Версия
v2.9.2_v1.10
Ohloh
Активное сообщество
Да . Проект, начатый как Specs (v1) в середине 2007 года, а затем развивающийся до более общей структуры, как Specs2 в 2010 году. В проекте есть несколько комиттеров (хотя в первую очередь им руководит Эрик Торреборре) и вспомогательные ресурсы, такие как группа Google, блог и корпоративная поддержка проекта.
пример
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
|
package org.scalabound.scatdd.specs2import org.scalabound.scatdd.FizzBuzzimport org.junit.runner.RunWithimport org.specs2.runner.JUnitRunner// package unitTest { |> Scala IDE will not pick the class up as runnable if I sub-package it like this 🙁@RunWith(classOf[JUnitRunner])class FizzBuzzJUnitSpec extends org.specs2.mutable.Specification { "Multiples of both three and five" should { "print 'FizzBuzz'" in { FizzBuzz.eval(15) must_== "FizzBuzz" } } "Multiples of three only" should { "print 'Fizz'" in { FizzBuzz.eval(12) must_== "Fizz" } } "Multiples of five only" should { "print 'Buzz'" in { FizzBuzz.eval(10) must_== "Buzz" } } "Non multiples of five or three" should { "print the number back" in { FizzBuzz.eval(11) must_== "11" } }}// package acceptanceTest { |> Scala IDE will not pick the class up as runnable if I sub-package it like this 🙁@RunWith(classOf[JUnitRunner])class FizzBuzzUATSpec extends org.specs2.Specification { def is = "This specification is to check the FizzBuzz evaluator" ^ p^ "The FizzBuzz evaluator should" ^ "process a multiple of both three and five to return FizzBuzz" ! e1^ "process a multiple of three only to return Fizz" ! e2^ "process a multiple of five only to return Buzz" ! e3^ "process a non multiple of three or five to return the input" ! e4^ end def e1 = FizzBuzz.eval(15) must_== "FizzBuzz" def e2 = FizzBuzz.eval(12) must_== "Fizz" def e3 = FizzBuzz.eval(10) must_== "Buzz" def e4 = FizzBuzz.eval(11) must_== "11"}@RunWith(classOf[JUnitRunner])class FizzBuzzDataTableSpec extends org.specs2.Specification with org.specs2.matcher.DataTables { def is = "Fizz Buzz testing with DataTables" ! e1 // note: when the first column of a DataTable is a String, '!!' needs to be used instead of '!' def e1 = "spec name" || "input val" | "expected output" | "Multiple of both three and five" !! 15 ! "FizzBuzz" | "Multiple of three only" !! 12 ! "Fizz" | "Multiple of five only" !! 10 ! "Buzz" | "Non multiple of five or three" !! 11 ! "11" |> { (a, b, c) => FizzBuzz.eval(b) must_== c // (a, b, c) is a structural match on the table }} |
Обратная связь
Обычно болевые точки, с которыми я сталкивался, были в Scala IDE, а не в Specs2. В частности, я изначально хотел включить разные типы тестов в один и тот же исходный файл, но различать по разным подпакетам. К сожалению, Scala IDE не получил субпакеты, так что это был не стартер. Одна небольшая странность заключалась в невозможности изменить порядок моих аргументов для спецификации спецификации DataTable.
Обновление : благодаря Эрику Торреборре это было решено с помощью !! вместо ! когда тип String используется для первого столбца в DataTable !! Это было небольшое раздражение, хотя.
В противном случае, спецификации 2 выглядят зрелыми, с хорошей поддержкой инструментов и, скорее всего, я выберу «оболочку» для тестирования. Я нашел API по умолчанию для спецификаций понятным и простым в использовании, и мне понравилось разделение тестов на выражения, оцененные для их поддержки или опровержения. Ницца.
Сравнения
RSpec , JBehave , easyb , Instinct , JUnit
<
SCALATEST
В двух словах
- Обобщенная структура для Java и Scala, в которой используются различные черты для объединения нескольких различных стилей и стратегий тестирования. Из коробки поддерживаются тесты TDD, BDD, функциональные, интеграционные TestNG и JUnit.
Ссылка на сайт
Версия v1.7.2
Ohloh
http://www.ohloh.net/p/scalatest
Активное сообщество
Да Это фреймворк второго поколения, созданный Биллом Веннерсом в 2001 году в рамках проекта SuiteRunner. Активно поддерживаются форумы, доступные через: http://www.scalatest.org/community.
пример
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
package org.scalabound.scatdd.scalatestimport org.junit.runner.RunWithimport org.scalatest.FunSpecimport org.scalatest.junit.JUnitRunnerimport org.scalabound.scatdd.FizzBuzz@RunWith(classOf[JUnitRunner])class FizzBuzzScalaTest extends FunSpec { describe('A FizzBuzz processor') { it('should return 'FizzBuzz' from a mulitple of three and five') { assert(FizzBuzz.eval(15) == 'FizzBuzz') } it('should return 'Fizz' from a multiple of three only') { assert(FizzBuzz.eval(12) == 'Fizz') } it('should return 'Buzz' from a multiple of five only') { assert(FizzBuzz.eval(10) == 'Buzz') } it('should return the stringified input from a non multiple of three or five') { assert(FizzBuzz.eval(11) == '11') } }} |
Обратная связь
Я использовал только один тип спецификации, и он казался одновременно ясным и лаконичным. Язык, продиктованный этим API ( опишите .. это .. ), был простым, но немного неловким на первом сайте. Я также предпочитаю более четкое различие между моими тестами и утверждениями (это вопрос вкуса). Тем не менее, было бы трудно найти более простую и «дружественную» среду, которая позволила бы команде Java начать работать с первого раза.
Сравнения
SCALACHECK
В двух словах
- Основанная на спецификации структура генерации тестов для Scala и Java. Библиотека была первоначально вдохновлена QuickCheck в Haskell.
Ссылка на сайт
https://github.com/rickynils/scalacheck#readme
Версия
v2.9.0-1-1.9
Ohloh
http://www.ohloh.net/p/scalacheck
Активное сообщество
Да , но в основном это связано с Рикардом Нильссоном. Похоже, что нет поддержки форума для этого проекта.
Обновление: благодаря @Daniel Sobral здесь есть (фактически) группа Google в поддержку ScalaCheck!
пример
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
package org.scalabound.scatdd.scalacheckimport org.scalabound.scatdd.FizzBuzzimport org.scalacheck.ConsoleReporter.testReportimport org.scalacheck.Prop.forAllimport org.scalacheck.Prop.propBooleanimport org.scalacheck.ConsoleReporterimport org.scalacheck.Testobject FizzBuzzScalaCheck { val propFizzBuzzCheck = forAll { n: Int =>{ if(n % 15 == 0) FizzBuzz.eval(n) == 'FizzBuzz' else if(n % 3 ==0) FizzBuzz.eval(n) == 'Fizz' else if(n % 5 ==0) FizzBuzz.eval(n) == 'Buzz' else '' + n == FizzBuzz.eval(n) } } def main(args : Array[String] ) = { ConsoleReporter.testStatsEx('blah', testReport(Test.check(propFizzBuzzCheck))) } } |
Обратная связь По сравнению с другими фреймворками, мне потребовалось некоторое время, чтобы поработать с ним (имейте в виду, что я бегал с другими через несколько минут!). Основными источниками моей боли были:
- Нет очевидной поддержки JUnit из коробки
- Первоначально я запускал свои тесты как приложение Scala (то есть, что-то, что расширяло приложение ), хотя продолжало
1
GenException(java.lang.NullPointerException)from the ConsoleReporter whenever I tried to run my tests. - Всякий раз, когда я пытался добавить слишком много условий к своему оператору импликации, я обнаруживал, что генерировалось недостаточно тестов для проверки моего свойства (отсюда и довольно неуклюжий пример, который я привожу ).
Сказав все это, я все еще считаю эту структуру уникальной и действительно ценной. В нескольких тестовых прогонах я регистрировал сгенерированные входы, и Scalacheck действительно великолепен (достаточный диапазон входов, сгенерированных и пропущенных). Это была, вероятно, самая сложная структура из трех, но она также предлагала такие функции, которые я, безусловно, хотел бы использовать снова и снова. Вероятно, в следующий раз я запустил бы это через Specs!
Сравнения
Java QuickCheck , JUnit quickcheck
Вывод
В заключение, все три фреймворка намного понятнее (или выразительнее), чем сравнительные фреймворки, которые я лично использовал в Java ранее. Если бы я пытался заставить команду «перейти» в Scala, я бы выбрал ScalaTest. Если бы я работал с командой, которая чувствовала себя немного более комфортно со Scala, я бы пошел по маршруту Specs2. В любом случае я бы попытался использовать ScalaCheck для генерации тестов (хотя в идеале абстрагироваться от одной из других платформ). В любом случае я могу понять, почему использование тестовых сред Scala помогает сформировать мнение о командах, прогрессирующих в Scala на предприятии. Я надеюсь, что этот отзыв был полезным и не слишком сухим. Как всегда, лучшая «проверка» — это идти по пути самостоятельно (если только ScalaCheck не сделает это за вас!). Удачи с вашим TDD и счастливого взлома!
Ссылка: ScaTDD: взгляд на три основных тестовых среды в Scala от нашего партнера по JCG Кингсли Дэвиса в блоге Scalabound .