Sie sind auf Seite 1von 20

http://betterspecs.

org/br/
http://slideplayer.com.br/slide/13381/
http://www.railsonmaui.com/tips/rails/capybara-phantomjs-poltergeist-rspec-rails-tips.html
http://pt.slideshare.net/fnando/testando-rails-apps-com-rspec

O que so testes?
Quais so os tipos de testes?

Testes Unitrios;
Testes de Integrao;
Testes Funcionais;

Teste de Performance

Testes de Aceitao

Webrat ou Selenium para controlar testes de aceitao

TDD (Test -Driven Development)


Desenvolvimento Orientado a Testes
Metodologia de escrever testes primeiro, e depois escrever o cdigo em seu aplicativo para fazer os testes
passarem. Desta forma, voc sempre ter uma rede de segurana construda e atualizada para que voc
possa dormir melhor noite, quando voc, ou algum, modificar o seu cdigo.

BDD (Behavior-Driven Development)


BDD essencialmente o mesmo que o TDD, mas escreve testes sob uma perspectiva de "histria de
usurio", que ajuda a resolver um monte de problemas de desenvolvimento de software comum.

Por qu testar?

http://blog.andolasoft.com/2014/06/rails-things-you-must-know-about-tdd-and-bdd.html

What is TDD (Test-Driven Development) ?


TDD is a way of designing the code by writing a test which expresses what
you intend the code to do. It defines a set of rules for developing software in
which test cases are written before any code and the only code written will be
enough to make the tests pass.
TDD is basically a software development technique that relies on the
repetition of a very short development cycle. In this technique, first the
developer starts by writing a failing automated test case (Red), implement the
simplest solution that will pass the test cases (Green) and then finally
improves or refactor the code (Refactor).RED-GREEN-REFACTOR is the
main agenda for TDD.
Tools to use:
There are some popular gems available to implement TDD in Ruby on
Railslike rspec-rails, capybara, factory_girl_rails, spork, launchy etc
Example:
Below is the code snippet for writing controller tests, like this:
1

describe ArticlesController do

it "renders the index template" do

get :index

response.should render_template("index")

end

end

What is BDD (Behavior-Driven Development)?


BDD extends Test driven development by writing test cases in a way anyone
can understand.With the help of BDD, software development is managed by
both business interests and technical insight. It focuses and associates
behavioral specifications with each unit of software under development.

Basically BDD is an Agile software development technique that encourages


collaboration between developers, QA and non-technical or business
participants in a software project. It extends TDD by writing test cases in a
natural language that non-programmers can read. In other way it is like story
writing.
The main thing to know is that BDD is meant to eliminate issues that TDD
might cause.
Tools to use:
Some popular gems are available to implement BDD in Rails are rpsec-rails,
factory_girl_rails, cucumber-rails, guard-cucumber, mocha etc
Example:
Below is the code snippet for writing the BDD:
01
#articles.feature

02
Given an article exists called "Testing Demonstration"

03
04

When I visit the list of articles


Then I should see an article called "Testing Demonstration"

05
06

#article_steps.rb

07

Given /^an article exists called "(.+)"$/ do |title|

08

FactoryGirl.create(:article, title: title)

09

end

10

When /^I visit the list of articles$/ do

11
12

visit articles_path
end
Then /^I should see an article called "(.+)"$/ do |title|

13
page.should have_content title

14

end

15

TDD or BDD, which is better?


The main difference between TDD and BDD is the business readability factor.

BDDs main draw is that the specifications or features are separate from the
test code, so the product owners can provide or review the specification
without having to go through code. TDD has a similar mechanism, but instead
you describe a step with a Describe, Context or It block that contains the
business specification, and then immediately have the code that executes that
statement.
Few drawbacks of TDD are as follows:

Big time investment: For the simple case you lose about 20% of the actual
implementation, but for complicated cases you lose much more.

Additional Complexity: For complex cases, test cases are harder to calculate.

Design Impacts: Sometimes the design is not clear at the start and evolves as you go
along this will force you to redo your test which will generate a big time lose.

Continuous Tweaking: For data structures and black box algorithms unit tests would be
perfect, but for algorithms that tend to change, this can cause a big time investment that
one might claim is not justified.

Verdict
If you are the sole developer and a product owner too, then you should go for
TDD. Its easier for a technical person to understand, which is an advantage in
keeping things scoped and under control. Thus keeps you out of messing up
with RegExs for test steps. On the flip side, you should go with BDD, if you
are building this for a client, and they are hands-on with regard to the
specifications.

gem 'database_cleaner' # Database Cleaner


gem 'capybara'

# DOM Dominator

#gem 'capybara-webkit'
gem 'selenium-webdriver'
# gem 'poltergeist'
#gem 'phantomjs', require: 'phantomjs/poltergeist'

`faker`, `guard-rspec`, `launchy`, and `factory_girl_rails` are all optional gems that will be super
helpful to you when writing your specs. Brief summaries below:
Faker: generates interesting fake data for testing purposes, from Lorem Ipsum to names and
emails. https://github.com/stympy/faker
Guard-Rspec: Runs your specs for you automatically when you make changes to your
application code. https://github.com/guard/guard-rspec
Launchy: Enables the save_and_open_page command with Capybara, which will live preview
the page as Capybara/Rspec sees it. https://github.com/copiousfreetime/launchy
FactoryGirl: Great gem by ThoughtBot that replaces the default Rails fixtures with more
extensible factories. https://github.com/thoughtbot/factory_girl
https://github.com/thoughtbot/factory_girl_rails

Teste group
gem
gem
gem
gem
gem
gem

'rspec-rails'
'factory_girl_rails'
'faker'
'capybara'
'guard-rspec'
'launchy'

gem 'selenium-webdriver'
gem 'database_cleaner'

Why install in two separate groups? rspec-rails and factory_girl_rails are used in
both the development and test environments. Specifically, they are used in

development by generators well be utilizing shortly. The remaining gems are only used
when you actually run your specs, so theyre not necessary to load in development.
This also ensures that gems used solely for generating code or running tests arent
installed in your production environment when you deploy to your server

So what did we just install?

rspec-rails includes RSpec itself in a wrapper to make it play nicely with


Rails 3.
factory_girl_rails replaces Rails default fixtures for feeding test data to the
test suite with much more preferable factories.
faker generates names, email addresses, and other placeholders for
factories.
capybara makes it easy to programatically simulate your users interactions
with your application.
launchy does one thing, but does it well: It opens your default web browser
upon failed integration specs to show you what your application is rendering.
guard-rspec watches your application and tests and runs specs for you
automatically when it detects changes.

Ill cover each of these in more detail in future posts, but in the meantime our
application has access to all the supports necessary to build a solid test suite.
Next up: Creating our test database.

Nextand this is optionalI like to change RSpecs output from the default
format to the easy-to-read documentation format. This makes it easier to see
which specs are passing and which are failing; it also provides an attractive
outline of your specs foryou guessed itdocumentation purposes.
Open .rspec to add the following line:
--format documentation

One last setup step: Telling Rails to generate spec files for us.

Generators
Now that weve got RSpec installed and configured, lets tell Rails to use it to
generate starter files for our applications test suite (instead of the default
TestUnit). While were at it, well tell Rails to create a factory corresponding to
each new model we create with Rails generate command.
Open config/application.rb and include the following code inside the
Application class:

config.generators do |g|
g.test_framework :rspec,
:fixtures => true,
:view_specs => false,
:helper_specs => false,
:routing_specs => false,
:controller_specs => true,
:request_specs => true
g.fixture_replacement :factory_girl, :dir => "spec/factories"
end

Can you guess what this code is doing? Heres a rundown:

specifies to generate a fixture for each model (using a


Factory Girl factory, instead of an actual fixture)
:view_specs => false says to skip generating view specs. I wont cover
them in this book; instead well use request specs to test interface elements.
:helper_specs => false skips generating specs for the helper files Rails
generates with each controller. As your comfort level with RSpec improves,
consider changing this option to true and testing these files.
:routing_specs => false omits a spec file for your config/routes.rb file.
If your application is simple, as the one in this book will be, youre probably
safe skipping these specs. As your application grows, however, and takes
on more complex routing, its a good idea to incorporate routing specs.
And finally, g.fixture_replacement :factory_girl tells Rails to generate
factories instead of fixtures, and to save them in
the spec/factories directory.
:fixtures => true

Generators
Once the environment is set. Its time to generate the testing files. There are different test types including,
model , view, controller,and integeration tests. Other types of tests are request, mailer and helper tests.

They are written as per requirements to cover every aspect of the application. This article will cover
commands and examples related to the most commonly used type of Rspec Tests.
-rails generate rspec:model model_name
-rails generate rspec:controller contoller_name
-rails generate rspec:view folder_name view_name
-rails generate integration_test feature_name

Execution Commands
To run specific tests from command line following commands should be used:
Models: bundle exec rspec spec/models/search_phrase_spec.rb
Controllers: bundle exec rspec spec/controllers/users_controller_spec.rb
Views: bundle exec rspec spec/views/search_phrases/index.html.erb_spec.rb
Integration: bundle exec rspec spec/features/search_phrases_spec.rb

The Naming convention for the Rspec Testing files:


Models: modelname_spec.rb
Controllers: controllername_controller_spec.rb
Views: viewname.html.extensionname_spec.rb
Integeration: featurename_spec.rb

Test Models With RSpec in Ruby on Rails


AUG 7TH, 2014

Testing is a good pratice. You should be doing it. It will make you a better
programmer and save you a great deal of headache as your web app grows up. It
is especially important when working alongside other programmers. Testing is
not perfect though so dont try to be perfect. Just get started, and you will
improve as time goes on.
How should I be testing?
- Using RSpec & factorygirl.
- Testing the Model.
Installation
Add rspec-rails and factorygirl to both the :development and :test groups in the
Gemfile:
Gemfile
1group :development, :test do
2 gem 'factory_girl_rails', '4.2.1'
3 gem 'rspec-rails', '~> 3.0.0'
4end

Download and install by running command:

1bundle install

Initialize the spec/ directory (where specs will reside) with:


1rails generate rspec:install

This adds the following files which are used for configuration:
- .rspec
- spec/spec_helper.rb
- spec/rails_helper.rb
Generators
Once installed, RSpec and factorygirl will generate spec files instead of
Test::Unit test files when run commands like: rails generate
model

and rails generate controller are used.

Example:
1rails generate model Post

After you run the command above this adds the following directory and file:
- spec/models/posts.rb
- spec/factories/posts.rb
Lets get started the Model testing
Assume we have three Models such as post.rb, category.rb, categorization.rb:
post.rb
1class Post < ActiveRecord::Base
2 validates :title, length: { minimum: 10, maximum: 100 }, presence: true, uniqueness: true
3 validates :body, length: { minimum: 20, maximum: 200 }
4 validates :status, length: { minimum: 2, maximum: 20 }, presence: true
5 validates :category_id, presence: true
6
7 has_many :categorizations
8 has_many :categories, through: :categorizations
9
10 scope :search_by_title, -> (title) { where("(title like ?) OR title in (?)", "%#{title}%", title.split) }
11end
category.rb

1class Category < ActiveRecord::Base


2 validates :name, length: { minimum: 10, maximum: 50 }, presence: true, uniqueness: true
3 validates :short_name, length: { minimum: 10, maximum: 50 }, presence: true, uniqueness: true
4 validates :description, length: { maximum: 200 }
5
6 has_many :categorizations
7 has_many :posts, through: :categorizations
8end
categorization.rb
1class Categorization < ActiveRecord::Base
2 validates :category_id, presence: true
3 validates :post_id, presence: true
4
5 belongs_to :category
6 belongs_to :post
7end

Next, we define default factorygirl object for each Models in spec/factories/:


posts.rb
1FactoryGirl.define do
2 factory :post do
3

title 'Ruby on Rails'

body 'Ruby on Rails is good'

status 'open'

category_id 1

7 end
8end
categories.rb
1FactoryGirl.define do
2 factory :category do
3

id 1

name 'programming'

short_name 'programming'

description 'computer programming'

7 end
8end
categorizations.rb

1FactoryGirl.define do
2 factory :categorization do
3

category_id '1'

post_id '1'

5 end
6end

Here, how we test each Models in spec/models/:


post.rb
1require 'spec_helper'
2
3describe Post, 'validation' do
4 it { should ensure_length_of(:title).is_at_least(10) }
5 it { should ensure_length_of(:title).is_at_most(100) }
6 it { should validate_presence_of(:title) }
7 it { should validate_uniqueness_of(:title) }
8
9 it { should ensure_length_of(:body).is_at_least(20) }
10 it { should ensure_length_of(:body).is_at_most(200) }
11
12 it { should ensure_length_of(:status).is_at_least(2) }
13 it { should ensure_length_of(:status).is_at_most(20) }
14 it { should validate_presence_of(:status) }
15
16 it { should validate_presence_of(:category_id) }
17end
18
19describe Post, 'association' do
20 it { should have_many(:categorizations) }
21 it { should have_many(:categories).through(:categorizations) }
22end
23
24describe Post, 'column_specification' do
25 it { should have_db_column(:title).of_type(:string).with_options(length: { minimum: 10, maximum:
26100 }, presence: true, uniqueness: true) }
27 it { should have_db_column(:body).of_type(:text).with_options(length: { minimum: 20, maximum:
28200 }) }
29 it { should have_db_column(:status).of_type(:string).with_options(length: { minimum: 2, maximum:
3020, presence: true }) }

31 it { should have_db_column(:category_id).of_type(:integer) }
32
33 it { should have_db_index(:title).unique(true) }
34end
35
36describe Post, '.search_by_name' do
37 before(:each) do
38

FactoryGirl.create(:post, title: 'Ruby on Rails')

39 end
40
41 it 'returns post that match with title' do
42

Post.search_by_title('Ruby on Rails').count.should eql 1

43 end
44
45 it 'returns post that like title' do
46

Post.search_by_title('ruby on rails').count.should eql 1

47 end
48
49 it 'returns post when title is blank' do
50

Post.search_by_title('').count.should eql 1

51 end
52
53 it 'returns empty when title is not match' do
Post.search_by_title('not match').count.should eql 0
end
end
category.rb
1require 'spec_helper'
2
3describe Category, 'validation' do
4 it { should ensure_length_of(:name).is_at_least(10) }
5 it { should ensure_length_of(:name).is_at_most(50) }
6 it { should validate_presence_of(:name) }
7 it { should validate_uniqueness_of(:name) }
8
9 it { should ensure_length_of(:short_name).is_at_least(10) }
10 it { should ensure_length_of(:short_name).is_at_most(50) }
11 it { should validate_presence_of(:short_name) }
12 it { should validate_uniqueness_of(:short_name) }

13end
14
15describe Category, 'association' do
16 it { should have_many(:categorizations) }
17 it { should have_many(:posts).through(:categorizations) }
18end
19
20describe Category, 'column_specification' do
21 it { should have_db_column(:name).of_type(:string).with_options(length: { minimum: 10, maximum:
2250 }, presence: true, uniqueness: true) }
23 it { should have_db_column(:short_name).of_type(:string).with_options(length: { minimum: 10,
24maximum: 50 }, presence: true, uniqueness: true) }
it { should have_db_column(:description).of_type(:text).with_options(length: { maximum: 200 }) }
end
categorization.rb
1require 'spec_helper'
2
3describe Categorization, 'validation' do
4 it { should validate_presence_of(:category_id) }
5 it { should validate_presence_of(:post_id) }
6end
7
8describe Categorization, 'association' do
9 it { should belong_to(:category) }
10 it { should belong_to(:post) }
11end
12
13describe Categorization, 'column_specification' do
14 it { should have_db_column(:category_id).of_type(:integer).with_options(presence: true) }
15 it { should have_db_column(:post_id).of_type(:integer).with_options(presence: true) }
16end

To run Models specs use the following command:


1rspec spec/models

You should get back the response something like:

For more detail about RSpec, FactoryGirl.


So far so good, Weve already created 40 models specs to test model. :)

Test Routes With RSpec in Ruby on Rails


JUL 30TH, 2014

Most Ruby on Rails developers dont test their routes, they focus on Model
testing, Controller testing, Features or View testing, Helper testing, and try to
catch every possible scenarios.
I would like to show how to test route separately.
Sample routes.rb:
routes.rb
1resources :products

Here is routes lists thats have been created:


1

root

posts GET

products#index
/products(.:format)

POST /products(.:format)

4 new_post GET
5edit_post GET

products#index
products#create

/products/new(.:format)

products#new

/products/:id/edit(.:format) products#edit

post GET

/products/:id(.:format)

PUT

DELETE /products/:id(.:format)

/products/:id(.:format)

products#show
products#update
products#destroy

Testing for each routes in routing/products_routing_spec.rb:

products_routing_spec.rb
1require 'spec_helper'
2
3describe "routing to products" do
4 it "routes /products to products#index" do
5

expect(get: "/products").to route_to(

controller: "products",

action: "index"

9 end
10
11 it "routes /products/1 to products#show" do
12

expect(get: "/products/1").to route_to(

13

controller: "products",

14

action: "show",

15

id: "1"

16

17 end
18
19 it "routes /products/new to products#new" do
20

expect(get: "/products/new").to route_to(

21

controller: "products",

22

action: "new"

23

24 end
25
26 it "routes /products to products#create" do
27

expect(post: "/products").to route_to(

28

controller: "products",

29

action: "create"

30

31 end
32
33 it "routes /products/1/edit to products#edit" do
34

expect(get: "/products/1/edit").to route_to(

35

controller: "products",

36

action: "edit",

37

id: "1"

38

39 end
40
41 it "routes /products/1 to products#update" do
42

expect(put: "/products/1").to route_to(

43

controller: "products",

44

action: "update",

45

id: "1"

46

47 end
48
49 it "routes /products/1 to products#destroy" do
50

expect(delete: "/products/1").to route_to(

51

controller: "products",

52

action: "destroy",

53

id: "1"

54

55 end
56end

Testing unroutable:
routes.rb
1resources :products, except: [:show]
products_routing_spec.rb
1it "does not routes /products/1 to products#show" do
2 expect(:get => "posts/1").not_to be_routable
3end

So far so good, Let enjoy the routes testing in your Ruby on Rails application. :)

Acceptance/Feature Test, Integration Test, Unit Test, Smoke Test,


Regression Test
OCT 14TH, 2013

1. What is Acceptance/Feature test?


Is the testing use to test the customers specific scenarios when a user story has
been correctly implemented. A story can have one or many acceptance tests,
whatever it takes to ensure the functionality works.
2. What is Integration test?
Is the testing use to expose defects in the interfaces and interaction between
integrated components (modules).

3. What is Unit test?


Also known as component testing, refers to tests that verify the functionality of a
specific section of code, usually at the function level. In an object-oriented
environment, this is usually at the class level. These types of tests is used to
ensure that the specific function is working as expected. One function might have
multiple tests.
4. What is Smoke test?
Is the quick testing to make sure everything looks okay before you get involved
in the more testing.
5. What is Regression test?
Is the testing to make sure you havent broken anything. Everything that used to
work should still work.

Test and Behaviour Driven Development (TDD/BDD)


OCT 12TH, 2013

1. What is TDD/BDD?
Express expected behaviour before writing code.
2. Why is TDD/BDD a good thing?
- Enjoy more efficient and predictable course of development.
- Find and fix bugs faster.
- Prevent bugs from reappearing.
- Improve the design of our software.
- Reliable document.
3. How do we do TDD/BDD?
- Write test programs.
- Run the tests automatically.
Workflow/Processing
TDD

BDD

http://robots.thoughtbot.com/how-we-test-rails-applications
http://everydayrails.com/2012/03/19/testing-series-rspec-models-factory-girl.html
http://cassiomarques.wordpress.com/2008/09/18/factory-girl-para-models-com-has_many/
http://devblog.orgsync.com/2014/01/13/write-faster-tests-factory-context/
http://blog.joshsoftware.com/2011/05/13/testing-associations-with-factory-girl/
http://stackoverflow.com/questions/13308768/factorygirl-populate-a-has-many-relationpreserving-build-strategy
http://www.arkhitech.com/a-brief-introduction-to-basics-of-rspec-in-ruby-on-rails
http://brandonhilkert.com/blog/7-reasons-why-im-sticking-with-minitest-and-fixtures-in-rails/

Use the rspec command to run your specs:


bundle exec rspec
By default the above will run all _spec.rb files in the spec directory. For more details
about this see the RSpec spec file docs.
To run only a subset of these specs use the following command:
# Run only model specs
bundle exec rspec spec/models
# Run only specs for AccountsController
bundle exec rspec spec/controllers/accounts_controller_spec.rb