Top Banner
http://www.urubatan.com.br [email protected] Transformando os pepinos do cliente no código de testes da aplicação com Cucumber Rodrigo Urubatan
62

Transformando os pepinos do cliente no código de testes da sua aplicação

May 06, 2015

Download

Technology

Slides da palestra apresentada no AgileBrazil 2010 sobre BDD, Cucumber e testes de aplicações .NET, Java e Rails com o cucumber
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: Transformando os pepinos do cliente no código de testes da sua aplicação

http://www.urubatan.com.br [email protected]

Transformando os pepinos do cliente no código de testes da aplicação com

Cucumber

Rodrigo Urubatan

Page 2: Transformando os pepinos do cliente no código de testes da sua aplicação

Sobre Urubatan

Trabalho com desenvolvimento desde 1997, já desenvolvi sistemas em diversas linguagens, como Delphi, C, C++, PHP, ASP, ColdFusion, Assembly, Leather, Java e Ruby.

Atualmente trabalho com pesquisa e desenvolvimento na HP, utilizando principalmente Java, e com Ruby em outros projetos e cursos.

Alem de ser o autor do livro "Ruby On Rails: Desenvolvimento fácil e Rápido de aplicações web"

Page 3: Transformando os pepinos do cliente no código de testes da sua aplicação

O cliente tem um problema a resolver

Page 4: Transformando os pepinos do cliente no código de testes da sua aplicação

Descobrindo os problemas

Reuniões com o cliente

Definição do Project

Backlog

Agile Business Analysis

User Stories

Lista do que deve ser feito

Cenários de uso do

sistema

Page 5: Transformando os pepinos do cliente no código de testes da sua aplicação

Behavior Driven Development

Page 6: Transformando os pepinos do cliente no código de testes da sua aplicação

Cenário: Login

Scenario: Login of existent user

Given I am on the login page

When I provide valid credentials

And I press "Login"

Then I should be redirected to "the home

page"

Page 7: Transformando os pepinos do cliente no código de testes da sua aplicação

Pensando melhor na feature

Page 8: Transformando os pepinos do cliente no código de testes da sua aplicação

Feature Login

Feature: Login

In order to make some money

As the service provider

I want existing users to be able to access the system

Scenario: Login of existent user

Given I am on the login page

When I provide valid credentials

And I press "Login"

Then I should be redirected to "the home page"

Scenario: Login of inexistent user

Given I am on the login page

When I provide invalid credentials

And I press "Login"

Then I should be redirected to "the login page"

Page 9: Transformando os pepinos do cliente no código de testes da sua aplicação

Tudo faz parte de um conjunto

Page 10: Transformando os pepinos do cliente no código de testes da sua aplicação

Qual o ferramental completo?

• Integração continua

• Testes de aceitação automatizados

• Relatório dos testes

• Deploy automatico

Page 11: Transformando os pepinos do cliente no código de testes da sua aplicação

Ciclo de implementação

1. Montar o backlog de features a serem implementadas

2. Priorizar as features

3. Pegar uma das features para implementar

4. Escrever os cenários/Testes de aceitação para a feature

5. Executar os cenários

6. Escrever código o suficiente para um cenário/teste passar

7. Executar os cenários novamente

8. Repetir passos 6 e 7 até que todos os cenários estejam passando

Page 12: Transformando os pepinos do cliente no código de testes da sua aplicação

Exemplo com Ruby on Rails

1. Criar uma aplicação Rails

2. Configurar o suporte ao cucumber

3. Criar features

4. Executar os testes

5. Implementar as features

6. Executar os testes

7. Repetir passos 4 a 6 até que o sistema esteja pronto

Page 13: Transformando os pepinos do cliente no código de testes da sua aplicação

Criar uma aplicação Rails

rails new rails_sample

Page 14: Transformando os pepinos do cliente no código de testes da sua aplicação

Configurar o ambiente e a aplicação

Instalar gems:

gem install rspec –version 2.0.0.beta.8

gem install rspec-rails –version 2.0.0.beta.8

gem install capybara database_cleaner cucumber-railscucumber spork launchy

Remover o arquivo “Gemfile”

Executar:

ruby script/rails generate cucumber:install --capybara --rspec

Page 15: Transformando os pepinos do cliente no código de testes da sua aplicação

Feature Scaffold

rails generate cucumber:feature user name:string

login:string password:string description:text

email:string

Page 16: Transformando os pepinos do cliente no código de testes da sua aplicação

Geração espontânea de testes

Page 17: Transformando os pepinos do cliente no código de testes da sua aplicação

Feature: Manage users

In order to [goal]

[stakeholder]

wants [behaviour]

Scenario: Register new user

Given I am on the new user page

When I fill in "Name" with "name 1"

And I fill in "Login" with "login 1"

And I fill in "Password" with "password 1"

And I fill in "Description" with "description 1"

And I fill in "Email" with "email 1"

And I press "Create"

Then I should see "name 1"

And I should see "login 1"

And I should see "password 1"

And I should see "description 1"

Page 18: Transformando os pepinos do cliente no código de testes da sua aplicação

And I should see "email 1"

Scenario: Delete user

Given the following users:

|name|login|password|description|email|

|name 1|login 1|password 1|description 1|email 1|

|name 2|login 2|password 2|description 2|email 2|

|name 3|login 3|password 3|description 3|email 3|

|name 4|login 4|password 4|description 4|email 4|

When I delete the 3rd user

Then I should see the following users:

|Name|Login|Password|Description|Email|

|name 1|login 1|password 1|description 1|email 1|

|name 2|login 2|password 2|description 2|email 2|

|name 4|login 4|password 4|description 4|email 4|

Page 19: Transformando os pepinos do cliente no código de testes da sua aplicação

Executar as features existentes

rake cucumber

Mostra quais testes passaram e qais falharam e

porque.

Page 20: Transformando os pepinos do cliente no código de testes da sua aplicação

cucumber –f pretty

Page 21: Transformando os pepinos do cliente no código de testes da sua aplicação

Implementar as features

rails generate scaffold user name:string login:string

password:string description:text email:string

Page 22: Transformando os pepinos do cliente no código de testes da sua aplicação

Cadastro Automágico

Page 23: Transformando os pepinos do cliente no código de testes da sua aplicação

Executar as features existentes

rake cucumber

Mostra quais testes passaram e qais falharam e

porque.

Page 24: Transformando os pepinos do cliente no código de testes da sua aplicação

cucumber –f pretty

Page 25: Transformando os pepinos do cliente no código de testes da sua aplicação

De volta ao Login

Page 26: Transformando os pepinos do cliente no código de testes da sua aplicação

Pedindo ajuda ao Cucumber

Page 27: Transformando os pepinos do cliente no código de testes da sua aplicação

Cucumber Ruby Back-End

When /^I provide valid credentials$/ do

fill_in('login', :with => 'admin')

fill_in('password', :with => 'admin')

end

Then /^I should be redirected to "([^\"]*)"$/ do |page_name|

current_path = URI.parse(current_url).path

current_path.should == path_to(page_name)

end

When /^I provide invalid credentials$/ do

fill_in('login', :with => 'admin1')

fill_in('password', :with => 'admin')

end

Page 28: Transformando os pepinos do cliente no código de testes da sua aplicação

Implementando a tela de login

rails generate controller session new

Editando o arquivo routes.rb

resource :sessions, :controller => :session

resources :users

match 'login' => redirect('/sessions/new'), :as =>

:login

root :to => „users#index‟

Page 29: Transformando os pepinos do cliente no código de testes da sua aplicação

Editando a view (new.html.erb)

<%= form_tag :action => :create do %>

<label for="login">Login:</label><input

type="text" id="login" name="login"/><br/>

<label for="password">Password:</label><input

type="password" id="password"

name="password"/><br/>

<input type="submit" value="Login"/>

<% end %>

Page 30: Transformando os pepinos do cliente no código de testes da sua aplicação

O controller (session_controller.rb)

class SessionController < ApplicationController

def new

end

def create

login = params[:login]

password = params[:password]

u = User.where("login = :login and password = :password", :login => login, :password => password).first

if u

redirect_to root_path

else

redirect_to new_sessions_path

end

end

end

Page 31: Transformando os pepinos do cliente no código de testes da sua aplicação

Resultado

Page 32: Transformando os pepinos do cliente no código de testes da sua aplicação

Dados de exemplo

Feature: Login

In order to make some money

As the service provider

I want existing users to be able to access the system

Background:

Given there is an user with name "admin" and password "admin"

Scenario: Login of existent user

Given I am on the login page

When I provide valid credentials

And I press "Login"

Then I should be redirected to "the home page"

Scenario: Login of inexistent user

Given I am on the login page

When I provide invalid credentials

And I press "Login"

Then I should be redirected to "the new session page"

def path_to(page_name)

case page_name

when /the home\s?page/

'/'

when /the new user page/

new_user_path

when /the new session page/

new_sessions_path

Given /^there is an user with name "([^\"]*)" and password

"([^\"]*)"$/ do |login, password|

User.create :login => login, :password => password

end

Page 33: Transformando os pepinos do cliente no código de testes da sua aplicação

Tudo Pronto!

Page 34: Transformando os pepinos do cliente no código de testes da sua aplicação

Exemplo Web com Java

1. Criar um projeto Web Dinâmico com eclipse (ou outra IDE Java)

2. Copiar a pasta features do projeto Rails

3. Configurar cucumber para testar aplicação Java

4. Executar cucumber

5. Implementar Login

6. Executar cucumber

7. Implementar cadastro de usuários

8. Executar cucumber

Page 35: Transformando os pepinos do cliente no código de testes da sua aplicação

Automação do browser

require 'capybara'

require 'capybara/dsl'

include Capybara

Capybara.current_driver = :selenium

Capybara.app_host = 'http://www.google.com'

Capybara.run_server = false

visit('/')

Page 36: Transformando os pepinos do cliente no código de testes da sua aplicação

Configurar o Cucumber

require 'rspec'

require 'capybara/cucumber'

require 'capybara/session'

require 'sqlite3'

require "selenium-webdriver"

require 'cucumber/web/tableish'

Capybara.default_selector = :css

Capybara.app_host = 'http://localhost:8080'

Capybara.run_server = false

# "before all"

Before do

db = SQLite3::Database.new "sample_db.sqlite3"

db.execute( "delete from users;" )

db.close

Capybara.current_driver = :selenium

end

# "after all"

After do

Capybara.use_default_driver

end

Page 37: Transformando os pepinos do cliente no código de testes da sua aplicação

Configurar os caminhosEditar o arquivo paths.rb para que fique assim:

module NavigationHelpers

def path_to(page_name)

case page_name

when /the home page/

'/'

when /the login page/

'/login'

when /the new user page/

'/users/new'

when /the users page/

'/users/'

when /the new session page/

'/login'

else

raise "Can't find mapping from \"#{page_name}\" to a path.\n" +

"Now, go and add a mapping in #{__FILE__}"

end

end

end

World(NavigationHelpers)

Page 38: Transformando os pepinos do cliente no código de testes da sua aplicação

Setup do Banco de dados

package commandLine;

import java.sql.Connection;

import java.sql.DriverManager;

import java.sql.SQLException;

import java.sql.Statement;

public class DbSetup {

public static void main(String[] args) throws ClassNotFoundException, SQLException {

Class.forName("org.sqlite.JDBC");

Connection conn = DriverManager.getConnection("jdbc:sqlite:sample_db.sqlite3");

Statement stat = conn.createStatement();

stat.executeUpdate("drop table if exists users;");

stat.executeUpdate("create table users (name varchar(200), login varchar(200), password varchar(200), description text, email varchar(200));");

}

}

Page 39: Transformando os pepinos do cliente no código de testes da sua aplicação

Servidor HTTP Embedded

package commandLine;

import org.eclipse.jetty.server.Handler;

import org.eclipse.jetty.server.Server;

import org.eclipse.jetty.server.handler.DefaultHandler;

import org.eclipse.jetty.server.handler.HandlerCollection;

import org.eclipse.jetty.webapp.WebAppContext;

public class Main {

public static void main(String[] args) throws Exception {

Server server = new Server(8080);

WebAppContext wac = new WebAppContext("WebContent", "/");

HandlerCollection handlers = new HandlerCollection();

Handler[] handlerArray = new Handler[] {wac, new DefaultHandler()};

handlers.setHandlers(handlerArray);

server.setHandler(handlers);

server.start();

}

}

Page 40: Transformando os pepinos do cliente no código de testes da sua aplicação

Alteração do login_steps.rb

require 'sqlite3‘

When /^I provide valid credentials$/ do

fill_in('login', :with => 'admin')

fill_in('password', :with => 'admin')

end

Then /^I should be redirected to "([ \̂"]*)"$/ do |page_name|

current_path = URI.parse(current_url).path

current_path.should == path_to(page_name)

end

When /^I provide invalid credentials$/ do

fill_in('login', :with => 'admin1')

fill_in('password', :with => 'admin')

end

Given /^there is an user with name "([^\"]*)" and password "([^\"]*)"$/ do |login, password|

db = SQLite3::Database.new "sample_db.sqlite3"

db.execute( "insert into users(login,password) values ( ?, ? )", login, password )

db.close

end

Page 41: Transformando os pepinos do cliente no código de testes da sua aplicação

Criando o servlet de login

package sample_servlets;

public class LoginServlet extends HttpServlet {

private static final long serialVersionUID = 1L;

@Override

protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

RequestDispatcher disp = req.getRequestDispatcher("WEB-INF/jsps/login.jsp");

disp.forward(req, resp);

}

@Override

protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

String login = req.getParameter("login");

String password = req.getParameter("password");

Connection conn = null;

try {

Class.forName("org.sqlite.JDBC");conn = DriverManager.getConnection("jdbc:sqlite:sample_db.sqlite3");

PreparedStatement pstmt = conn.prepareStatement("select * from users where login=? and password=?");

pstmt.setString(1, login);pstmt.setString(2, password);ResultSet query = pstmt.executeQuery();

if (query.next()) {resp.sendRedirect("/");} else {resp.sendRedirect("/login");}

} catch (Exception e) {e.printStackTrace();resp.sendRedirect("/login");} finally {

if (conn != null)

try {conn.close();} catch (SQLException e) {e.printStackTrace();

resp.sendRedirect("/login");}

}}}

Page 42: Transformando os pepinos do cliente no código de testes da sua aplicação

Criação da página de login

Criar o arquivo WEB-INF/jsps/login.jsp com o seguinte conteúdo:

<html>

<head>

<title>Sample Login Page</title>

</head>

<body>

<form method="POST"><label for="login">Login</label><input

type="text" id="login" name="login" /><br />

<label for="password">Password</label><input type="password"

id="password" name="password" /><br />

<input type="submit" value="Login"/></form>

</body>

</html>

Page 43: Transformando os pepinos do cliente no código de testes da sua aplicação

Executar o cucumber

cucumber features\login.feature

Page 44: Transformando os pepinos do cliente no código de testes da sua aplicação

Implementando o Gerenciamento de

usuários

• Alterar os steps do cucumber para que insiram os

dados no banco correto

• Exectar o cucumber

• Criar um servlet UsersServlet

• Criar as JSPs necessárias

• Executar o cucumber

Page 45: Transformando os pepinos do cliente no código de testes da sua aplicação

Cucumber gerenciamento de usuários

Page 46: Transformando os pepinos do cliente no código de testes da sua aplicação

Exemplo .NET

• Utilizando o

VisualStudio.NET

express

• .NET MVC 2

• LINQ to SQL mapping

• Cucumber + Watir

• SQL Server Express Data

File

• Utilizaremos as mesmas

features e cenários

• Primeiro

implementaremos o

Login

• Depois o gerenciamento

de usuários

Page 47: Transformando os pepinos do cliente no código de testes da sua aplicação

Criação do projeto

• Criar um novo projeto C# MVC 2 Blank

• Criar um controller de nome HomeController,

uma View de nome Index para este controller e

uma MasterPage

• Dentro de Model criar um “New Item” “Link to

SQL Classes” de nome DataClasses1

Page 48: Transformando os pepinos do cliente no código de testes da sua aplicação

Dados para o projeto

• Criar um banco SQL Server de nome sample_db

• Criar um Data Connection para este banco de dados

• Criar um DSN ODBC para o mesmo banco

• Em Data Connections, na pasta Tables criar uma nova tabela de nome users com os campos

• id, int, identity

• name, nchar(200)

• login, nchar(200)

• password, nchar(200)

• email, nchar(200)

• description, ntext

• Arrastar a tabela para o LINQ Designer e renomear para Users

Page 49: Transformando os pepinos do cliente no código de testes da sua aplicação

Instalação de dependencias

gem install watir ruby-odbc

Page 50: Transformando os pepinos do cliente no código de testes da sua aplicação

Configuração do cucumber

• Baixar exemplos do Watircuke de http://github.com/richdownie/watircuke

• Baixar arquivos de features/support/ para o mesmo diretório no projeto

• env.rb

• paths.rb

• watircuke.rb

• Criar diretório features/step_definitions

• Copiar os arquivos .feature do projeto de exemplo rails.

Page 51: Transformando os pepinos do cliente no código de testes da sua aplicação

Executando o Cucumber

Page 52: Transformando os pepinos do cliente no código de testes da sua aplicação

SQL Server pelo Ruby

require 'rubygems„

require „odbc„

@con = ODBC.connect('sample_db',nil,nil)

Page 53: Transformando os pepinos do cliente no código de testes da sua aplicação

Começando a brincadeira

• Criar o arquivo

step_definitions/cucumber_steps.rb

• Colocar todos os steps que o cucumber disse

estarem pending quando executado pelo console

• Fazer o “merge” de todos os passos similares

utilizando as expressões regulares

Page 54: Transformando os pepinos do cliente no código de testes da sua aplicação

Given /^there is an user with name "([^\"]*)" and password "([^\"]*)"$/ do |login, password|

p = @con.proc("insert into users(login, password) values (?, ?)") {}

p.call(login, password)

end

Given /^I am on (.*)$/ do |page|

@browser.goto path_to(page)

end

When /^I provide valid credentials$/ do

find_text_field('login','admin')

find_text_field('password','admin')

end

When /^I press "([^\"]*)"$/ do |label|

find_button label

end

Then /^I should be redirected to "([^\"]*)"$/ do |page|

raise "Not on the expected page" unless @browser.url == path_to(page)

end

When /^I provide invalid credentials$/ do

find_text_field('login','admin2')

find_text_field('password','admin2')

end

Page 55: Transformando os pepinos do cliente no código de testes da sua aplicação

Criar o LoginController

DataClasses1DataContext dataClasses = new DataClasses1DataContext();

public ActionResult Index()

{

return View();

}

public ActionResult Create(String login, String password)

{

try{

Users u = dataClasses.Users.First(usr => usr.login == login && usr.password == password);

return Redirect("http://localhost:1467/");

}

catch (Exception e)

{

return RedirectToAction("Index");

}

}

Page 56: Transformando os pepinos do cliente no código de testes da sua aplicação

Criar a view Login/Index.aspx

<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/ViewMasterPage1.Master" Inherits="System.Web.Mvc.ViewPage<dynamic>" %>

<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">

System Login

</asp:Content>

<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">

<h2><%: ViewData["Message"] %></h2>

<form method="post" action="Login/Create">

<p> <label for="login">Login</label><input type="text" id="login" name="login"/> </p>

<p> <label for="password">Password</label><input type="password" id="password“ ame="password"/> </p>

<p><input type="submit" value="Login" /></p>

</form>

</asp:Content>

Page 57: Transformando os pepinos do cliente no código de testes da sua aplicação
Page 58: Transformando os pepinos do cliente no código de testes da sua aplicação

Criando o Cadastro de Usuários

• Criar um UsersController com os métodos padrão

• Implementar os métodos da forma mais simples

possível

• Implementar as views

• Executar o cucumber novamente para testar a

aplicação

Page 59: Transformando os pepinos do cliente no código de testes da sua aplicação

Código para o CucumberWhen /^I fill in "([ \̂"]*)" with "([^\"]*)"$/ do |field,value|

find_text_field field, value

end

Then /^I should see "([^\"]*)"$/ do |value|

raise "#{value} was not found in the document" unless @browser.text.include? value

end

Given /^the following users:$/ do |table|

table.hashes.eachdo |hash|

name = hash[:name]

login = hash[:login]

password = hash[:password]

description = hash[:description]

email = hash[:email]

@con.run( "insert into users(name,login,password,description,email) values ( ?, ?, ?, ?, ? )", name,login,password,description,email )

end

end

When /^I delete the 3rd user$/ do

@browser.goto path_to('the users page')

find_link('delete3')

end

Then /^I should see the following users:$/ do |table|

tbl = @browser.table(:id, 'usersList').to_a

idx = 1

table.hashes.each_with_index do |hash,index|

name = hash[:name]

login = hash[:login]

password = hash[:password]

description = hash[:description]

email = hash[:email]

raise "unexpected users list" unless tbl[idx][2]==name

raise "unexpected users list" unless tbl[idx][3]==login

raise "unexpected users list" unless tbl[idx][4]==password

raise "unexpected users list" unless tbl[idx][5]==description

raise "unexpected users list" unless tbl[idx][6]==email

idx += 1

end

end

Page 60: Transformando os pepinos do cliente no código de testes da sua aplicação

Executando o Cucumber

Page 62: Transformando os pepinos do cliente no código de testes da sua aplicação

Referências

• Meu livro - http://livro.urubatan.com.br• Meu blog - http://www.urubatan.com.br• Cucumber - http://wiki.github.com/aslakhellesoy/cucumber• Capybara- http://github.com/jnicklas/capybara• WebDriver -

http://code.google.com/p/selenium/wiki/RubyBindings• Watir - http://watir.com/• Watircuke - http://github.com/nofxx/watircuke• Rails – http://rubyonrails.org• ASP.NET MVC - http://www.asp.net/mvc