Qual é o Framework BDD mais maduro para .NET?

Temos usado o BDD – Behavior Driven Development (da perspectiva de Dan North) como um mecanismo para registrar os testes de aceitação do usuário e impulsionar o desenvolvimento em alguns projetos, com sucesso decente. Até hoje, embora não tenhamos automatizado os testes em si.

Agora estou olhando para automatizar os testes, mas não tenho certeza de qual estrutura de comportamento voltar. Até agora, NBehave parece ser o precursor – mas há outros que eu deveria estar olhando? Existe um ‘vencedor’ claro no momento?

A resposta rápida

Um ponto muito importante a mencionar é que existem dois tipos de desenvolvimento orientado pelo comportamento. Os dois sabores são xBehave e xSpec .

xBehave BDD: SpecFlow

O SpecFlow (muito semelhante ao pepino da pilha Ruby) é excelente em facilitar os testes xBehave BDD como Critérios de Aceitação. No entanto, não fornece uma boa maneira de escrever testes comportamentais em um nível de unidade. Existem algumas outras estruturas de teste do xBehave, mas o SpecFlow obteve muita tração.

BDD xSpec: MSpec

Objetivamente falando. Dadas as estruturas de especificações de contexto disponíveis, o MSpec tem sido o mais longo e é a estrutura de contexto / especificação mais amplamente usada na comunidade .Net.

A outra estrutura xSpec BDD: NSpec

Eu pessoalmente recomendaria o NSpec (inspirado diretamente pelo RSpec para Ruby). Divulgação completa, eu sou um dos autores do NSpec. Você pode realizar o BDD simplesmente usando NUnit ou MSTest … mas eles ficam um pouco aquém (é realmente difícil construir contextos incrementalmente). MSpec também é uma opção e é a estrutura de contexto / especificação mais madura para .Net. Mas há apenas algumas coisas que são mais simples no NSpec.

A longa resposta

Os dois sabores do BDD existem principalmente por causa dos benefícios ortogonais que eles fornecem.

Prós e Contras de xBehave (Sintaxe GWT)

Prós

  • ajuda a facilitar as conversas com o negócio através de um dialeto comum chamado (por exemplo, Dado …., E Dado …., Quando ……, E Quando ….., Então …., E depois)
  • o dialeto comum pode então ser mapeado para o código executável, o que prova para o negócio que você realmente terminou o que disse que terminaria
  • o dialeto é restritivo, então o negócio tem que desambiguar os requisitos e torná-lo adequado às sentenças.

Contras

  • Enquanto a abordagem xBehave é boa para conduzir Critérios de Aceitação de alto nível, os ciclos necessários para mapear o inglês para código executável via atributos inviabilizam a saída de um domínio no nível da unidade.
  • Mapear o dialeto comum para testes é PAINFUL (aumentar sua regex). Cada sentença criada pela empresa deve ser mapeada para um método executável por meio de atributos.
  • O dialeto comum deve ser rigidamente controlado para que o gerenciamento do mapeamento não saia do controle. Toda vez que você muda uma sentença, você tem que encontrar um método que se relacione diretamente com aquela sentença e conserte a correspondência regex.

Prós e Contras do xSpec (Contexto / Especificação)

Prós

  • Permite que o desenvolvedor crie um contexto incrementalmente. Um contexto pode ser configurado para um teste e algumas asserções podem ser executadas nesse contexto. Você pode então especificar mais contexto (construindo sobre o contexto que já existe) e depois especificar mais testes.
  • Nenhuma linguagem constritiva. Os desenvolvedores podem ser mais expressivos sobre como uma determinada parte de um sistema se comporta.
  • Nenhum mapeamento é necessário entre o inglês e um dialeto comum (porque não há um).

Contras

  • Não tão acessível pelo negócio. Vamos enfrentá-lo, o negócio não gosta de desambiguar o que eles querem. Se nós dermos a eles uma abordagem baseada em contexto para o BDD, então a sentença seria apenas “Apenas faça funcionar”.
  • Tudo está no código. A documentação do contexto está entrelaçada dentro do código (é por isso que não precisamos nos preocupar com o mapeamento do inglês para o código)
  • Não é tão legível dado um palavreado menos restritivo.

Amostras

O Kata Bowling é um ótimo exemplo.

Amostra SpecFlow

Aqui está como seria a especificação no SpecFlow (novamente, isso é ótimo como um teste de aceitação, porque ele se comunica diretamente com o negócio):

Arquivo de recurso

O arquivo de recurso é o dialeto comum para o teste.

 Recurso: Cálculo da Pontuação 
   Para conhecer meu desempenho
   Como jogador
   Eu quero que o sistema calcule minha pontuação total

 Cenário: Jogo de sarjeta
   Dado um novo jogo de boliche
   Quando todas as minhas bolas estão caindo na sarjeta
   Então minha pontuação total deve ser 0

 Cenário: Pino Único
   Dado um novo jogo de boliche
   Quando eu acertei exatamente 1 pino
   Então minha pontuação total deve ser 1

Arquivo de definição de etapas

O arquivo de definição de etapas é a execução real do teste, esse arquivo inclui os mapeamentos para o SpecFlow

[Binding] public class BowlingSteps { private Game _game; [Given(@"a new bowling game")] public void GivenANewBowlingGame() { _game = new Game(); } [When(@"all of my balls are landing in the gutter")] public void WhenAllOfMyBallsAreLandingInTheGutter() { _game.Frames = "00000000000000000000"; } [When(@"I've hit exactly 1 pin")] public void When1PinIsHit() { _game.Frames = "10000000000000000000"; } [Then(@"my total score should be (\d+)")] public void ThenMyTotalScoreShouldBe(int score) { Assert.AreEqual(score, _game.Score); } } 

Amostra MSpec, xSpec, Contexto / Especificação

public class describe_BowlingKata { public static Game game; public class when_all_balls_land_in_the_gutter : describe_BowlingKata { Establish ctx = () => game = new Game(); Because of = () => game.Frames = "00000000000000000000"; It should_have_a_score_of_0 = () => game.Score.ShouldBe(0); } public class when_a_single_pin_is_hit : describe_BowlingKata { Establish ctx = () => game = new Game(); Because of = () => game.Frames = "10000000000000000000"; It should_have_a_score_of_1 = () => game.Score.ShouldBe(1); } }
public class describe_BowlingKata { public static Game game; public class when_all_balls_land_in_the_gutter : describe_BowlingKata { Establish ctx = () => game = new Game(); Because of = () => game.Frames = "00000000000000000000"; It should_have_a_score_of_0 = () => game.Score.ShouldBe(0); } public class when_a_single_pin_is_hit : describe_BowlingKata { Establish ctx = () => game = new Game(); Because of = () => game.Frames = "10000000000000000000"; It should_have_a_score_of_1 = () => game.Score.ShouldBe(1); } } 

Amostra NSpec, xSpec, Contexto / Especificação

Aqui está um exemplo NSpec do mesmo kata de boliche:

class describe_BowlingGame : nspec { Game game; void before_each() { game = new Game(); } void when_all_my_balls_land_in_the_gutter() { before = () => game.Frames = "00000000000000000000"; it["should have a score of 0"] = () => game.Score.should_be(0); } void when_a_single_pin_is_it() { before = () => game.Frames = "10000000000000000000"; it["should have a score of 1"] = () => game.Score.should_be(1); } }
class describe_BowlingGame : nspec { Game game; void before_each() { game = new Game(); } void when_all_my_balls_land_in_the_gutter() { before = () => game.Frames = "00000000000000000000"; it["should have a score of 0"] = () => game.Score.should_be(0); } void when_a_single_pin_is_it() { before = () => game.Frames = "10000000000000000000"; it["should have a score of 1"] = () => game.Score.should_be(1); } } 

À medida que você faz mais e mais BDD, você verá que ambos os sabores xBehave e xSpec do BDD são necessários. O xBehave é mais adequado para testes de aceitação, o xSpec é mais adequado para testes de unidade e design dirigido por domínio.

MSpec vs NSpec

Métricas objetivas como idade e estabilidade devem ser um fator, e eu gostaria de encorajar todos a levar isso em consideração. Mas, por favor, leve também em consideração que os frameworks mais novos podem fornecer uma API mais sucinta, melhor uso de construções de linguagem e construir lições aprendidas para frameworks anteriores . MSpec fornece construções de Dado, Porque, Isto e Limpeza .. mas eles têm um custo: boot estática para todos os membros, explosão de class, e é sintaticamente rígida por causa de seu uso exclusivo de delegates. Você verá que os testes MSpec mais simples são mais simples no NSpec. Aqui está um conjunto de testes mais complexo escrito em MSpec e NSpec.

Uma comparação de xUnit, MSpec e NSpec: https://gist.github.com/amirrajan/6701522

Links Relevantes

RSpec vs Cucumber (histórias RSpec)

BDD com pepino e rspec – quando isso é redundante?

Confira o SpecFlow .

É uma ferramenta inspirada no Pepino que visa fornecer uma abordagem pragmática e sem fricção ao Desenvolvimento Orientado a Testes de Aceitação e Desenvolvimento Dirigido por Comportamento para projetos .NET atualmente.

A integração do VisualStudio parece especialmente promissora.

O StoryQ parece uma boa alternativa ao NBehave com sua interface Fluent. Eu definitivamente iria dar uma olhada.

Eu não acho que há um ‘vencedor’ realmente. Outras estruturas incluem o projeto SpecUnit.NET e MSpec também está mostrando a promise com o início de um adaptador Gallio . Tecnicamente, uma vez que o IronRuby está no horizonte, o rSpec pode ser uma opção para aqueles que estão preparados para ir ao limite. NBehave + NSpec pode ser o framework mais antigo com a melhor automação, embora eu tenha me encontrado lutando contra a syntax excessivamente detalhada.

Eu verificaria todos eles e escolheria a estrutura mais adequada ao seu estilo de projeto. Eles são todos OSS, então é difícil perder, o benefício real é simplesmente mudar para o BDD.

Eu pessoalmente recomendo BDDfy que é excelente na minha opinião! É open source, suporta convenções e descrições de cenários fluentes, cobre tanto testes de aceitação como testes unitários. Você pode encontrá-lo no GitHub .

O Robot Framework também pode ser usado com o IronPython para fazer ATDD ou BDD em .Net. Eu acho que os resources de expressão do Robot Framework são melhores que por exemplo. SpecFlow ou NSpec . Ele não força você a usar uma determinada syntax, mas usa uma abordagem orientada por palavras-chave. Se você estiver testando aplicativos da Web, ele possui Selenium2Library, que fornece ligações ao Selenium WebDriver.

Há também o Specter , que define uma DSL no Boo para tornar tudo mais natural.

Eu geralmente vou em favor do NBehave, combinado com o MbUnit e qualquer estrutura de DI / mocking que você precise. É um comentário justo de Jim Burger que NBehave é muito detalhado, e eu me vejo usando cut-and-paste às vezes. Ainda assim, funciona muito bem – eu estou usando o plug-in ReSharper da Gallio, então eu só tenho uma janela extra aparecendo. Ainda não tentei com ccnet, no entanto.

Confira esta postagem do blog e seus comentários para ideias inspiradoras: http://haacked.com/archive/2008/08/23/introducing-subspec.aspx/

O Concordion.NET não suporta apenas o BDD, mas também o ATDD: http://assertselenium.com/2012/11/05/difference-between-tdd-bdd-atdd/ As especificações são escritas em linguagem simples usando HTML. IMHO este é um dos benefícios do Concordion.NET. Os documentos HTML podem ser organizados em uma estrutura navegável para criar um sistema de documentação vivo . E, como os testes são executados no sistema, você pode ter certeza de que a documentação está sempre atualizada.

Estou começando a minha primeira apresentação no BDD com um pequeno aplicativo com minha equipe. As ferramentas que escolhemos para fazer o trabalho são: Specflow com Selenium Webdriver para xBehave stories e MSpec com Machine.Fakes.Moq para um contêiner de automocking para nossos testes de unidade xSpec. Com o Resharper para ser nosso runner de histórias e runner de especificações devido à integração suportada pelo Specflow e MSpec. Ter integração nativa no visual studio com R # é uma característica fundamental para nós.

Como nosso design é todo MVC3, também aplicaremos o padrão de separação do orquestrador aos nossos controladores MVC . Isso nos permitirá escrever especificações diretamente contra o orquestrador. Então, para nós, escrever histórias diretamente contra o uso do aplicativo.

Confira também UBADDAS, específico para UAT encontrado em

https://github.com/KernowCode/UBADDAS

com uma explicação aqui

http://kernowcode.wordpress.com/ (em junho de 2014)

Você pode escrever um teste como este

 [Test] public void IWantToRegisterANewUser() { var user = new User(); ICustomer customer = new Customer(); SoThat(MyBusinessValue.IncreaseCustomerBase) .As(user) .Given(customer.Register) .When(customer.Confirm_Registration) .Then(customer.Login); } 

e produz este

 I want to register a new user so that Increase customer base as user given Register customer when Confirm customer registration then Login customer 

Como agora estou lidando com o BDD para testes de sistema para aplicativos críticos de segurança, só posso compartilhar minha experiência de que você não deve subestimar o poder de “testes escritos em uma linguagem natural” em vez de “código”.

Sempre nos concentramos em oferecer uma linguagem de resources, que qualquer um possa entender sem nenhum conhecimento técnico ou experiência em programação (veja o exemplo do specflow acima) e fizemos bem em fazê-lo. Além do fato de que nunca expliquei a syntax a ninguém, todos entenderam imediatamente o significado do teste, do desenvolvedor, do gerente e até do testador.

Eu evitaria de qualquer forma um teste escrito em uma linguagem de programação como os exemplos MSpec acima. Se eu aparecer com um teste como este no escritório de um gerente, ele vai me expulsar. Mas ele está interessado em ler testes baseados em Gherkin-Syntax. Quanto mais pessoas conseguirem ler e modificar os testes, melhor.

Por último, mas não menos importante, esses testes são portáveis ​​para qualquer outra linguagem de programação, qualquer outra plataforma, qualquer outra ferramenta de automação de teste sem nenhuma alteração.

Mais uma vez, a resposta é mais uma vez:

Não se preocupe com a ferramenta e seus resources, escolha uma ferramenta que permita alternar facilmente para outra ferramenta a qualquer momento sem perder informações. Ferramentas vêm e vão, meus testes devem durar mais tempo. 🙂

Eu posso recomendar o uso do SpecFlow. Você tem access total à completa Biblioteca .Net e a todos os seus resources, seus testes permanecem portáteis. Isso pode lhe dar uma vantagem sobre soluções totalmente portáteis, como o Robot Framework, se você não se importar com a portabilidade. No entanto, você sempre pode melhorar a estabilidade e a portabilidade de um sistema usando diferentes ferramentas para desenvolvimento e teste. Portanto, testar um software .Net com uma abordagem de BDD baseada em python pode ser uma boa (ou até a melhor) ideia em alguns casos.

No entanto, o SpecFlow mostrou-se estável e à prova de balas nos testes diários, incluindo testes de construção noturna, etc. em projetos de tamanho médio. Além disso, integra-se bem no Microsoft Unit Test Environment.