Pull to refresh

Comments 25

Недавно тоже смотрел что существует по этому поводу. На codeplex мрого интересного, и даже полностью идентичный проект nbehave.codeplex.com/
Спасибо за ссылку. Посмотрел на NBehave — это довольно большой фреймворк с полноценной реализацией поведения, своим раннером и плюшками, интересно. У меня идея была использовать синтаксис NUnit, но вместо блоков Arrange, Act, Assert использовать методы, по названиям которых проще понять какое поведение моделируется.
Мы используем NBehave в связке с NUnit. Получается что-то вроде такого (точный код на работе):

Код
[TestFixture]
class SomeTests{
  [Test]
  public void Test(){
    @"Given initial value is 5
         When multiply it by 2
         Then it should be 10
    ".Execute(In.Context<MultiplySteps>())
    }
}

[ActionSteps]
public class MultiplySteps{
  int _value; 
  [Given("initial value is $value")]
   public GivenInitialValue(int value){
     _value = value;
  }

  [When("multiply it by $mul")]
  public GivenInitialValue(int mul){
     _value = _value*mul;
  }
  
  [Then("it should be $expected")]
  public GivenInitialValue(int expected){
    Assert.IsTrue(_value==expected)
  }
}



Естественно, степов очень много. Вполне удобно писать интеграционные и функциональные тесты, но unit тесты писать кодом удобнее во много раз. Плюс слишком сложно искать соответствия между степами и реальным кодом (для отладки, например), даже есть самописный плагин для студии, который пытается помогать.
Да, выглядит интересно, но, наверное, сложно поддерживать. Если сценарий меняется нужно изменять названия строк в нескольких местах. А как с передачей объектов в качестве параметров? Хотя вряд ли тот, кто пишет спецификацию будет пытаться моделировать состояние объекта.
Степы обычно очень маленькие, что позволяет их комбинировать и уменьшает необходимость изменения существующих степов и спек. Если чего-то не хватает, гораздо проще дописать еще один степ для этого частного случая. Передавать объекты напрямую, конечно, не получится, но можно, например, сделать builder, которые описывается степами (например, мы так формируем сложный запрос к REST service, а ля «Когда запрашиваем данные с url и когда используем такую-то авторизацию и когда используем такие-то праметры»). Еще можно через DI c помощью степов построить нужный контейнер и дальше вытягивать объекты через него.

В качестве живого примера можно посмотреть на наши плагины, они доступны на гитхабе: github.com/TargetProcess/Target-Process-Plugins/blob/master/Plugins/Tp.PopEmail/Tp.PopEmail.Tests/BusinessScenarios/HandleEmailsFromUserFeature/WhenMailFromUserReceivedSpecs.cs
SpecFlow другой фреймворк и я его не пробовал. Мы используем NUnit в проекте и хочется использовать один фреймворк для тестов, тем более NUnit мне нравится. Плюс у Resharper нет нативной поддержки SpecFlow. Хотя NCrunch поддерживает его через интеграцию с NUnit, так что может и с Resharper будет работать. Стоит присмотреться? Чем он хорош?
Мы используем в проекте вместе с NUnit и Resharper, никаких проблем нет. По сути, SpecFlow-файл при сохранении генерирует .cs файл с NUnit-тестом. Хорош тем, что тесты получаются краткие и написаные языком, понятным как разработчикам, так и тестировщикам\аналитикам.
Specflow — хорош очень многим. Вы можете почитать на их сайте. Это порт на .net лидера bdd фреймворков кукумбера. Создана в рамках компании TechTalk. За приличное количество лет своего существования этот продукт эволюционировал до очень крутого уровня.

Я в документации по nbehave нашел только пару вещей, которой я не припомню в specflow — это Examples и возможности по вызову степов из юнит тестов — но так ли уж это надо — вопрос.
В свою очередь specflow имеет массу возможностей, которых нет в nbehave и главное новые очень быстро появляются — перечислять не хочется — почитайте на сайте.

Самое главное — он поддерживает большое количество тестовых провайдеров, в том числе MsTest и NUnut.
И различные платформы кроме .netMono, Silverlight, Windows Phone 7.
Да, подход основан на спецификациях, поведении. Я когда первый раз увидел MSpec не сразу сообразил как он работает, но идея отличная =)
Тоже давно баловался code.google.com/p/artspec/
Избавляет от плохо читаемых названий методов, но решил что MSpec интереснее.
В общем очередной велосипед.

Фреймворков для реализации подобного функционала целая пачка (NBehave, Specflow).
И они просты, легки в использовании и их поддерживают уважаемые сообщества.

Отправляйте наработку в свой архив и не вздумайте использовать на работе.
Как вспомню моду на самописные ORM в компаниях несколько лет назад так вздрогну.
Хотя нет — сейчас подумал — это может пригодится как раз если вам не нужен полноценный DSL, а нужно писать модульные тесты в BDD стиле.
Только вот зачем…
При правильной организации модульных тестов given — в предыницализации теста, when — одна строчка, then — мясо теста.
Наверно у вас просто неправильные тесты — раз понадобился такой странный механизм.
Я как раз и стараюсь создать и начать использовать DSL в проекте и двигаюсь в сторону DDD, но пока это все в зачаточном состоянии.

Чем плохи модульные тесты в BDD стиле?

При правильной организации модульных тестов given — в предыницализации теста, when — одна строчка, then — мясо теста.
Я так и написал, только не мясо а проверки (Assert).

Наверно у вас просто неправильные тесты — раз понадобился такой странный механизм.

Это неправильные пчелы и они дают неправильный мед

До этого использовал блок Arrange, в котором подготавливал данные для тестирование, блок Act и блок Assert где проверял результат теста. Все это происходило в одном методе — тесте. И когда инициализация занимает больше 15 строк кода читать такой тест становится неудобно. Но чем такие тесты неправильны?
В нормальном тесте инициализация не должна занимать 15 строк кода. Для тестового класса возможно. Но для этого есть специальный атрибут в тестовом фреймворке. Классический модульный тест тестирует один метод. Значит when шаг — одна строчка. Самый код будет в ассертах да. Это нормальный стиль — вы видите в одном тестовом методе весь тестовый случай — все три шага рядом. Так задумывалось изначально создателями mstest и nunit.
Нет смысла их разделять. Вопрос распухания инициализации конкретно решается другими средствами.
В общем очередной велосипед.

Да, конечно, я практически так и написал. Велосипеды создавать интересно ©
Интересно писать для себя. Но потом обязательно возникнет желание впихнуть в какой нибудь рабочий проект, продав как свои знания.
И это уже проблема. Вот вы же предложили распространить решение NuGet пакетом?
Вот вы же предложили распространить решение NuGet пакетом

Да, конечно. Для меня тесты в таком стиле читабельнее и удобнее. Без необходимости разбираться и работать с новыми фреймворками. Этот фактор может оказаться очень значимым в контексте проекта или команды.

И это уже проблема.

В чем вы видите проблему? Класс с минимальным количеством логики, который делает тесты понятнее. Да, я как раз и собираюсь использовать его в проекте. Для меня это сродни Extension методу для закрытого класса.
Это сейчас у вас класс с минимальным количеством логики. А завтра он вырастет в монстра — потому что любой продукт имеет свойство эволюционировать. Только код который будет заточен под ваше решение уже не переделать — и вы останетесь на продукте с ним навечно. Да чего я вам объясняю очевидные проблемы велосипедов.
Понятно что вас потом уже уволить не смогут — ведь только вы уже будете мастером по этому решению.

Без необходимости разбираться и работать с новыми фреймворками. — в вышеуказанных фреймворках разбираться ничуть не сложнее чем в том, что вы предложили. Можно статью на хабре даже короче написать. Посмотрите обзор — он очень прост.
Да чего я вам объясняю очевидные проблемы велосипедов.

Как минимум чтобы я прочитал и еще раз задумался. И, возможно, не только я. Спасибо.

Усложнять это решение у меня нет намерения. Благодаря комментариям к статья я узнал больше о BDD фреймворках и способах решить задачу похожим образом. Тем более атрибуты называются так же и если вдруг понадобиться более сложная функциональность перейти на SpecFlow, например не составит труда.

Я надеюсь что и другие читатели нашли для себя что-то полезное, так что, думаю, что статья вполне имеет место быть.
> если вдруг понадобиться более сложная функциональность

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

Все-таки хотел бы настоять на том, что SpecFlow — это не «когда… понадобиться более сложная функциональность», а готовый продукт для решения Вашей задачи сейчас.
Я обязательно еще ближе посмотрю на SpecFlow и NBehave. Сейчас у меня нет четкого понимания BDD и я не знаю BDD тесты должны быть модульными или интеграционными (возможно и то и то). Вопрос требует более глубокой проработки и я не хочу принимать опрометчивые решения.

В проекте сейчас мы пишем по большей части модульные тесты и мое решение было нацелено на то, чтобы сделать их читабельнее.
Sign up to leave a comment.

Articles