bdd com cucumber

Post on 25-May-2015

1.578 Views

Category:

Technology

1 Downloads

Preview:

Click to see full reader

DESCRIPTION

Introdução ao BDD com Cucumber

TRANSCRIPT

DesenvolvimentoBaseado em TestesBDD + CucumberEduardo Mendesedumendes@gmail.com

@dudumendes

Introdução

Agenda

BDDCucumber

@dudumendes

BDD

TDDAbordagem de desenvolvimento de software em que os testes direcionam a implementação do software

TDD

Favorece o design de software

Expressa o comportamento do código

Documenta o código

@dudumendes

Testes unitários

Uma forma de aplicar o TDD

Traduzem as expectativas dos desenvolvedores sobre o comportamento do código

Fragilidade: Muito acoplado à implementação

Não traduz as expectativas dos usuários

Expectativas dos usuários

Casos de Uso

Estórias de Usuário

Ambas não possuem mecanismos de validação que traduzam as expectativas dos usuários

@dudumendes

BDDBehaviour Driven Development

@dudumendes

BDDBehaviour Driven Design

@dudumendes

BDD

“Behaviour-Driven Development is about implementing an application by describing its behaviour from the perspective of its stakeholders.”

David Chemlimsky

BDD

“Desenvolvimento orientado a comportamento diz respeito a implementar uma aplicação pela descrição do seu comportamento a partir da perspectiva de seus stakeholders.”

David Chemlimsky

Entender o mundo a partir da visao do STK_HD

Para entregar COISAS UTEISEntender o seu domínioSeus desafios e oportunidadesAs palavras que ele usa para descrever o comportamento que ele quer da aplicação

Mais que da visão de um stakeholderDo ponto de vista de qualquer que está envolvido no projeto

Behaviour Driven Development

Uma abordagem no estilo TDD

Documentação executável

Melhora a comunicação dos times

Esclarece os mal-entendimentos entre clientes, especialistas de domínio, desenvolvedores

Pode ser utilizada por todos os envolvidos no projeto

@dudumendes

BDDPrincípios

Enough is enough

Deliver stakeholder value

It’s all behaviour

@dudumendes

BDDPrincípios

O bastante é o bastanteTrabalhar para alcançar as expectativas dos stakeholders, mas evitar fazer mais do que se é necessário fazer

Entregar valor ao stakeholderSe você está fazendo algo que não entrega valor ou não aumenta sua habilidade de entrega de valor, pare e faça outra coisa

Tudo é sobre comportamentoAssim como podemos descrever o comportamento a partir da perspectivas dos stakeholders, também podemos descrever o comportamento de um código a partir de outro código que o utiliza

@dudumendes

Ciclo do BDD

red

red

greenrefactor

green

refactor

Cenário

Passo

@dudumendes

BDDO Ciclo

Stakeholder e analista discutem os requisitos

os requisitos são organizados em funcionalidades (features)

podem ser quebradas em estórias

fazem sentido para o stakeholder

@dudumendes

BDDO Ciclo

Stakeholder, analista e testador determinam os escopos das estórias

o analista pensa na funcionalidade de forma geral

o testador pensa em cenários concretos, com valores de entradas e saída

@dudumendes

BDDO Ciclo

Cenários prioritários são identificados

Stakeholder especifica exatamente o que quer entregue

Desenvolvedores implementam o bastante para satisfazer os cenários e nada mais

@dudumendes

BDDO Ciclo

Desenvolvedores

Automatizam cenários que orientam o desenvolvimento

Descrevem comportamentos esperados

Implementam os comportamentos

Refatoram

@dudumendes

Processo do BDD

@dudumendes

Estórias no BDD

BDDEstórias e Comportamento

Estórias

Correspondem às Estórias de Usuário

Expressam o comportamento das explicações em alto nível

Necessidade de frameworks de estórias

Cucumber, JBehave

BDDEstórias e Comportamento

Comportamento (ou Spec)

Correspondem às expectativas em nível de classeExpressam o comportamento a nível de serviço/componente

Estórias e Comportamento

Estórias de Usuário

Formado por um conjunto de Cenários (Scenarios)

critérios de aceitaçãoCada cenários possui

“entradas”, eventos e “resultados”Utilizados em projetos ágeis

Behaviour

Expressado como métodos de testesDefine o que aplicação deve e não deve fazer

Estrutura de uma estóriaConnextra Format

Título

Narrativa

As a [algum_papel]I want [alguma_necessidade]So that [beneficio/valor_da_caracteristica]

Critérios de aceitação (cenários)

Given [alguma(s)_condicao(oes)]When [evento_ocorrer]Then [certifico_algum_resultado]

Estrutura de uma estória

Título

Narrativa

Como um [algum_papel]Eu quero [alguma_necessidade]Para que [beneficio/valor_da_caracteristica]

Critérios de aceitação (cenários)

Dado [alguma(s)_condicao(oes)_entrada]Quando [evento_ocorrer]Então [certifico_algum_resultado]

Ciclo do BDD

red

red

grerefactor

grerefactor

Cenário

Passo

@dudumendes

Cucumber

Cucumber

Framework BDD Open Source baseado em RSpec

Criado por Aslak Hellesøy

Versão atual 1.2.1

CucumberCaracterísticas

Implementação em Ruby

Estórias de usuário baseadas em textos

Suporte a Injeção de dependências

Cucumberem 03 passos

Escrever uma estória e executar a estória (.feature)

obter os snippets com os passos do teste

Criar o arquivos de passos a partir dos snippets

Dar implementação aos passos

@dudumendes

Cucumber em 03 passosPasso 1 - Escrever uma estória

Estrutura de uma estóriaNarrativa

As a [algum_papel]

I want [alguma_necessidade]

So that [beneficio/valor_da_caracteristica]

Cenário

Given [alguma(s)_condicao(oes)]

When [evento_ocorrer]

Then [certifico_algum_resultado]

Estrutura de uma estóriaNarrative:

In order to [beneficio/valor_da_caracteristica]

As a [algum_papel]

I want to [alguma_necessidade]

Scenario: Nome do Cenário

Given [alguma(s)_condicao(oes)]

When [evento_ocorrer]

Then [certifico_algum_resultado]

@dudumendes

Estórias no Cucumberarquivos

de texto com extensão “.feature”

localização

diretório features

o comando procura por um diretório “features”

execução

comando cucumber

busca o diretório

Cucumber em 03 passosPasso 1 - Escrever uma estória

Feature: greeter says hello

In order to test Cucumber As a developer I want a greeter to say hello

Scenario: greeter says hello Given a greeter When I send it the greet message Then I should see "Hello Cucumber"

gretter_say_hello.feature

@dudumendes

cucumber

@dudumendes

continuação: snippets

@dudumendes

Resultado

O cucumber encontrou a feature

tentou executá-la

mas não sabe como executá-la

O cucumber sugeriu algumas dicas do código

@dudumendes

Cucumber em 03 passosPasso 2 - Criar o arquivo de passos

@dudumendes

Estórias no Cucumberarquivos

em Ruby com sufixo “_steps”

localização

features/step_definitions

execução

comando cucumber

@dudumendes

Given /^a greeter$/ do pending # express the regexp above with the code you wish you hadend

When /^I send it the greet message$/ do pending # express the regexp above with the code you wish you hadend

Then /^I should see "(.*?)"$/ do |arg1| pending # express the regexp above with the code you wish you hadend

greeter_steps.rb

@dudumendes

Cucumber em 03 passosPasso 3 - Dar implementação às estórias

@dudumendes

Given /^a greeter$/ do @greeter = CucumberGreeter.newend

When /^I send it the greet message$/ do @message = @greeter.greetend

Then /^I should see "(.*?)"$/ do |greeting| @message.should == greetingend

greeter_steps.rb

@dudumendes

@dudumendes

class CucumberGreeter def greet "Hello Cucumber" end end

Given /^a greeter$/ do @greeter = CucumberGreeter.newend

When /^I send it the greet message$/ do @message = @greeter.greetend

Then /^I should see "(.*?)"$/ do |greeting| expect(@message).to eql greetingend

@dudumendes

Cucumber Passos

Escrever uma estória

Arquivo de texto de extensão .feature

Recuperar os snippets

Criar o arquivo de passos

Estórias no Cucumber

Estórias em arquivos de textos

01 Narrativa (Narrative)

* Cenários (Scenarios)

Narrativa

Opcional

As a, In order to, I want to

Cenários no CucumberCenários consistem em:

Título

Passos:Given, When, Then

And

é possível colocar then antes do when

Cenários podem depender de outros

Comentários (!-- )

@dudumendes

Gherkin

Feature:

Scenario:

Given When Then

Internacionalização

Inglês é o padrão

# language: pt

Aplicação

Step definitions

Features

@dudumendes

Gherkin

Feature

Scenario

Scenario Outline

Scenarios

Given

When

Then

And

But

|

“”

#

@dudumendes

Gherkin --i18n

cucumber --i18n pt

@dudumendes

Exercício

Criar uma versão em português para o Hello World

Esquema de CenáriosScenario Outline

É comum em testes de aceitação definir-se exemplos de cenários reais com valores para verificar o estado de pronto da aplicação

Neste caso é possível se utilizar esquemas de cenários

Esquemas de cenários

Nos cenários os parâmetros devem ser envolvidos com sinais “<” e “>”

Eles devem ser declarados como esquemas de cenários

Após um cenário informam-se os valores válidos para os parâmetros em um tabela determinada por “Cenários:”

@dudumendes

# language: pt

Funcionalidade: Depositar Dinheiro

Esquema do Cenário: Depositar Dinheiro

Dado um cliente especial com saldo atual de <saldo_inicial> reais Quando ele realizar um deposito no valor <deposito> reais Então o deposito deve ser realizado E o saldo da conta atualizado para <saldo_final> reais Cenarios: valores possiveis | saldo_inicial | deposito | saldo_final | | 200 | 100 | 300 | | 200 | 100 | 300 | | 200 | 100 | 300 | | 200 | 100 | 300 |

@dudumendes

O comando cucumber

@dudumendes

Organizando featuresComando cucumber sem opções

serão procurados todos os arquivos .rb e .feature abaixo do diretório features

gera snippets para features indefinidas

cada Cenário e Passo tem comentários no final da linha

localização do cenário

nome do arquivo e número da linha

@dudumendes

# language: pt

Funcionalidade: Futuro hospede reserva um quarto

A fim de proporcionar mais comodidade Como dono do hotel Eu gostaria que os futuros hospedes reservassem quartos pela internet

Cenario: Reserva com sucesso Dado um hotel com "10" quartos e "0" reservas

@dudumendes

Organizando features

@dudumendes

Organizando featuresComando cucumber sem opções

serão procurados todos os arquivos .rb e .feature

Para projetos pequenos

caminho mais simples é organizar os arquivos dentro do diretório features

Para projetos maiores

crie subdiretorios para cada feature

vários arquivos em cada diretório com um subconjunto de ceários coesos

@dudumendes

Organizando featuresfeatures

seguro

medico

dentario

vida

previdencia

prbl

vgbl

cucumber features

executa todos

cucumber features/seguro

apenas os de seguro

cucumber features/seguro/medico

somente os médicos

@dudumendes

A vida de um cenárioNo processo de software

Cada cenário de uma funcionalidade precisa ser descrito e aprovado

Durente a especificação, os cenários podem estar

pendentes de aprovação

em progresso

estados mistos em uma mesma feature

pode ser necessário testar um subjconjunto da suites de testes

@dudumendes

Tags para features/scenarios

É como uma annotation

pode ser utilizada para marcar features e/ou scenarios

scenarios herdam as tags de suas features

podem ser utilizadas para

@dudumendes

Tags

@aprovada @sprint_1

Funcionalidade: paciente solicita consulta

@em_progresso

Cenario: paciente seleciona horario disponivel

cucumber --tags @em_progresso

@dudumendes

Tagscucumber --tags @cuc, @umber

cucumber --tags @cuc || @umber

executa todos os cenário com @cuc OU @umber

cucumber --tags @cuc --tags @umber

cucumber --tags @cuc && @umber

executa todos os cenário com @cuc E @umber

cucumber --tags ~@umber

cucumber --tags !@umber

executa todos os cenário sem @umber

@dudumendes

Passo-a-passo

@dudumendes

GivenWhen

Then

@dudumendesPassosUm passo candidato (StepCandidate) de uma feature deve estar associado a uma implementação de passo em um arquivo de passos

feature_X.feature

Cenario: Cenario A

Dado um contexto

Quando algo acontecer

Então Alguma coisa acontece

Arquivo de Passos

cenario_a_steps.rb

Dado um contexto

Quando algo acontecer

Então Alguma coisa acontece

implementação

implementação

implementação

Esta associação é feita através de expressões regulares

@dudumendes

Passos

Um passo candidato (StepCandidate) de uma feature deve estar associado a uma implementação de passo em um arquivo de passos

Caso esteja: passed

Caso contrário: undefined

@dudumendes

Definição de passosCriação do arquivo de feature

Quando você cria uma feature

executa o cucumber

cenários indefinidos

passos indefinidos

snippets de código

@dudumendes

ExecutaCenário

Lê 1.º passoExiste

definição?

Lê próximopasso

PassoIndefinido

Pendente?Exceção lançada?

Existe outro passo

CenárioFalho

Executa código de definição do

passo

Não

Sim

SimNão

CenárioPendente

Sim

CenárioIndefinido

Sim

Não

Não

CenárioPassou

@dudumendes

# language: pt

Funcionalidade: Futuro hospede reserva um quarto

A fim de proporcionar mais comodidade Como dono do hotel Eu gostaria que os futuros hospedes reservassem quartos pela internet

Cenario: Reservar com sucesso Dado um hotel com "10" quartos e "0" reservas

@dudumendes

Definição de passosCriação do arquivo de passos

Cria-se o arquivo de passos

Dado /^um hotel com "(.*?)" quartos e "(.*?)"

reservas$/ do |total_de_quartos, total_de_reservas|

end

@dudumendes

Given / When / ThenO formato Connextra

Utilizados para descrever os passos de um teste de aceitação

servem para descrever o cenário de uma vida real

expressam comportamento esperado

@dudumendes

GivenDado

Indica algo que se aceita como verdadeiro e certo em um cenário

Dado que tenho R$ 20 em minha conta

Dado que a Terra é redonda

Dado que hoje é sábado

É uma setença que descreve um contexto para os eventos e saídas que serão exercitados nos cenários

Não são pré-condições

@dudumendes

WhenQuando

Indica o evento que ocorre naquele cenário

Quando eu saco R$ 10

Quando eu pulo da estratosfera

Melhor que se tenha um evento por cenário

melhor descrição da intenção de cada cenário

falhas não serão ocultadas quando mais que um evento for descrito

@dudumendes

ThenEntão

Indica uma saída esperada

Então eu devo ter R$ 5 no final

Então eu devo pular antes de sair da atmosfera

Pode haver mais que uma saída por cenário

mas devem ser coesas

@dudumendes

And / ButE / Mas

Podem ser utilizados para complementar a descrição do Given e do Then

Cenario: Reserva com sucesso

Dado um hotel com "10" quartos E com "0" reservas Quando um futuro hospede reservar "1" quarto Entao reservas será "1" E o número dos quartos será "9"

@dudumendes

@dudumendes

Passos compostos

@dudumendes

Passos Compostos

Em BDD, o autor de cenários deve possuir a liberdade de aprofundar o foco de um determinado cenário

esta situação pode ultrapassar o limite de um cenário inicial

um passo pode depender de passos utilizados em outros cenários

Neste contexto, os cenários compostos são úteis

@dudumendes

Passos Compostos

Passos compostos permitem criar grupos de execução de passos ligados a um único passo, o que pode ser muito útil e poderoso

@dudumendes

Funcionalidade: Logar na aplicacao

Cenário: Usuario existe

Dado que o usuario "dudumendes" existe Dado que eu informei o login "dudumendes"

Dado /^que o usuario "(.*?)" existe$/ do |nome| # ...end

Dado /^que eu informei o login "(.*?)"$/ do |nome| # ...end

@dudumendes

Cenário: Usuario existe

Dado que o usuario "dudumendes" existe Dado que eu informei o login "dudumendes"

Dado que "dudumendes" está logado

Dado /^que o usuario "(.*?)" existe$/ do |nome| # ...end

Dado /^que eu informei o login "(.*?)"$/ do |nome| # ...end

Dado /^que (.*?) está logado$/ do |nome| step "que o usuario #{nome} existe" step "que eu informei o login #{nome}"end

@dudumendes

Funcionalidade: Transferir Dinheiro

Cenário: Transferir Dinheiro

Quando eu seleciono "conta corrente" como conta de origem E eu seleciono "poupanca" como conta de destino E eu informo que a quantidade é 20 E solicito executar

Quando /^eu seleciono "(.*?)" como conta de origem$/ do |origem|end

Quando /^eu seleciono "(.*?)" como conta de destino$/ do |destino|end

Quando /^eu informo que a quantidade é (\d+)$/ do |valor|end

Quando /^solicito executar$/ doend

@dudumendes

Funcionalidade: Transferir Dinheiro

Cenário: Transferir Dinheiro

Quando eu seleciono "conta corrente" como conta de origem E eu seleciono "poupanca" como conta de destino E eu informo que a quantidade é 20 E solicito executar Cenário: Transferir Dinheiro Resumido

Quando eu transfiro 20 da "conta corrente" para a "poupanca"

@dudumendes

Quando /^eu transfiro (\d+) da (.*?) para a (.*?)$/ do |valor, origem, destino| step "eu seleciono #{origem} como conta de origem" step "eu seleciono #{destino} como conta de destino" step "eu informo que a quantidade é #{valor}" step "solicito executar"end

@dudumendes

ExercícioCompletar a feature da Transferência e fazer passar

@dudumendes

Hooks

@dudumendes

Hooks

Before

Executado antes de cada cenário

After

Executado depois de cada cenário

AfterStep

Executado após cada passo

@dudumendes

Before do puts "Isto executa antes de cada cenário"end

After do puts "Isto executa depois de cada cenário"end

AfterStep do puts "Isto executa depois de cada passo"end

Before(“@cuc”) do puts "Isto executa antes de cada cenário com @cuc"end

@dudumendes

BackgroundContexto, Cenario de Fundo

Before, After, AfterStep

Não possuem descrição na feature

Background

Similar ao Before

Permite escrever passos na feature

@dudumendes

Funcionalidade: Convidar amigos

Contexto: Usuario logado

Dado que "dudumendes" esta logado Cenário: Convidar alguem que já é amigo Cenário: Convidar alguem que ainda não é amigo

@dudumendes

Tabelas em passos

@dudumendes

Funcionalidade: Baralho

Cenário: tres do mesmo tipo ganha de dois pares

Dado uma mao com as seguintes cartas | valor | naipe | | 2 | CORACAO | | 2 | ESPADAS | | 2 | PAUS | | 4 | OUROS | | A | CORACAO |

E outra mao com as seguintes cartas | valor | naipe | | 2 | CORACAO | | 2 | ESPADAS | | 4 | PAUS | | 4 | OUROS | | A | CORACAO | Entao a primeira mao deve ganhar da segunda mao

@dudumendes

Dado /^uma mao com as seguintes cartas$/ do |table| # table is a Cucumber::Ast::Table pending # express the regexp above with the code you wish you hadend

Dado /^outra mao com as seguintes cartas$/ do |table| # table is a Cucumber::Ast::Table pending # express the regexp above with the code you wish you hadend

Entao /^a primeira mao deve ganhar da segunda mao$/ do pending # express the regexp above with the code you wish you had

@dudumendes

Dado uma mao com as seguintes cartas | valor | naipe | | 2 | CORACAO | | 2 | ESPADAS | | 2 | PAUS | | 4 | OUROS | | A | CORACAO |

[ { :valor => '2', :naipe => 'CORACAO'}, { :valor => '2', :naipe => 'ESPADAS'}, { :valor => '2', :naipe => 'PAUS'}, { :valor => '4', :naipe => 'OUROS'}, { :valor => 'A', :naipe => 'CORACAO'}]

@dudumendes

Dado /^uma mao com as seguintes cartas$/ do |cartas| cartas.hashes.each {|hash| @primeira_mao << Carta.new(hash) }end

Dado /^outra mao com as seguintes cartas$/ do |cartas| cartas.hashes.each {|hash| @segunda_mao << Carta.new(hash) }end

@dudumendes

Exercíciofazer passar a feature

@dudumendes

Exercício

@dudumendes

Criar a feature e fazer passarDados  os  negociantes:  |nome|rank||Larry|Estagio  3||Moe|Estagio  1||Curly|Estagio  2|Quando  os  negociantes  são  ordenados  pelo  nomeEntão  os  comerciantes  devem  vir  na  seguinte  ordem:|nome|rank||Curly|Estagio  2||Larry|Estagio  3||Moe|Estagio  1|

@dudumendes

Rails + cucumber + rspecpequena dose

@dudumendes

rails new showtime

@dudumendes

Gemfilegroup :development, :test do

gem "rspec-rails"

gem "webrat"

end

group :test do

gem "cucumber-rails"

gem ”database_cleaner”

end

@dudumendes

bundle install

rails generate rspec:install (dependencias do rspec)

rails generate cucumber:install (dependencias do cucumber)

rake db:migrate

rake db:test:prepare

rake spec

rake cucumber

@dudumendes

Funcionalidade: Descrições Como um frequentador de cinema Eu quero ver horarios precisos e concisos Para que eu possa encontrar filmes que se encaixem no meu horario

Cenário: Exibir minutos para horarios que não terminam em 00 Dado um filme Quando eu configuro o horario para "2012-10-10" às "2:15pm" Então o horario deve ser "October 10, 2012 2:15pm"

/features/horario.feature

@dudumendes

snippet

@dudumendes

features/step_definitions/horario_steps.rb

# encoding: utf-8# language: pt

Dado /^um filme$/ do @filme = Filme.create!end

Quando /^eu configuro o horario para "(.*?)" às "(.*?)"$/ do |data, hora| @filme.update_attribute(:horario_data, Date.parse(data)) @filme.update_attribute(:horario_hora, hora)end

Então /^o horario deve ser "([^"]*)"$/ do |horario| expect(@filme.horario).to eql horarioend

@dudumendes

Criar o Model Filme

rails g model filme horario_data:date horario_hora:time

Além do modelo criará o spec spec/model/filme_spec.rb

rake db:migrate

rake db:test:prepare

@dudumendes

app/models/filme.rb

class Filme < ActiveRecord::Base attr_accessible :horario_data, :horario_hora def horario "#{data_formatada} #{hora_formatada}" end def data_formatada horario_data.strftime("%B %d, %Y") end def hora_formatada horario_hora.strftime("%l:%M%p").strip.downcase end end

@dudumendes

Validando o modelo

@dudumendes

rails generate model Email de:text para:text mensagem:text

@dudumendes

require 'spec_helper'

describe Email do pending "add some examples to (or delete) #{__FILE__}"end

@dudumendes

require 'spec_helper'

describe Email do context "validações:" do

it "para é obrigatório"

it "para é válido com email válido"

it "para é inválido com email inválido"

it "mensagem é obrigatória"

endend

@dudumendes

@dudumendesrequire 'spec_helper'

describe Email do context "validações:" do

it "para é obrigatório" do email = Email.create expect(email).to have(1).error_on(:para) end

it "para é válido com email válido"

it "para é inválido com email inválido"

it "mensagem é obrigatória"

endend

@dudumendes

@dudumendes

class Email < ActiveRecord::Base attr_accessible :mensagem, :paraend

app/models/email.rb

@dudumendes

class Email < ActiveRecord::Base attr_accessible :mensagem, :para validates_presence_of :paraend

app/models/email.rb

@dudumendes

# encoding: utf-8

require 'spec_helper'

describe Email do context "validações:" do it "de é obrigatório" do email = Email.create expect(email).to have(1).error_on(:de) end it "para é obrigatório" it "mensagem é obrigatória"

it "de deve ser um email" do email = Email.create(:de => "de@email.com") expect(email).to have(:no).error_on(:de) end it "para deve ser um email" endend

@dudumendes

@dudumendes

describe Email do context "validações:" do it "para é obrigatório" do email = Email.create expect(email).to have(1).error_on(:para) end it "para é válido com email válido" do email = Email.create(:para => "para@email.com") expect(email).to have(:no).error_on(:para) end it "para é inválido com email inválido" it "mensagem é obrigatória" endend

@dudumendes

@dudumendes

# encoding: utf-8

require 'spec_helper'

describe Email do context "validações:" do it "para é obrigatório" do email = Email.create expect(email).to have(1).error_on(:para) end it "para é válido com email válido" do email = Email.create(:para => "para@email.com") expect(email).to have(:no).error_on(:para) end it "para é inválido com email inválido" do email = Email.create(:para => "invalido") expect(email).to have(1).error_on(:para) end it "mensagem é obrigatória" endend

@dudumendes

class Email < ActiveRecord::Base attr_accessible :mensagem, :para validates_presence_of :para validates_format_of :para, :with => /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\z/i, :allow_blank => trueend

@dudumendesdescribe Email do context "validações:" do it "para é obrigatório" do email = Email.create expect(email).to have(1).error_on(:para) end it "para é válido com email válido" do email = Email.create(:para => "para@email.com") expect(email).to have(:no).error_on(:para) end it "para é inválido com email inválido" do email = Email.create(:para => "invalido") expect(email).to have(1).error_on(:para) end it "mensagem é obrigatória" do email = Email.create expect(email).to have(1).error_on(:mensagem) end endend

@dudumendes

class Email < ActiveRecord::Base attr_accessible :mensagem, :para validates_presence_of :para validates_presence_of :mensagem validates_format_of :para, :with => /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\z/i, :allow_blank => trueend

@dudumendes

BibliografiaBEHAVIOUR-DRIVEN DEVELOPMENT. http://behaviour-driven.org/.

CHELIMSKY, David. The RSpec Book. PragBook, 2011.

JBEHAVE. http://jbehave.org/reference/.

PUGH, Ken. Lean-Agile Acceptance Test-Driven Development: better software through collaboration. Addison-Wesley, 2010.

top related