This is an overdue post that I wrote during my programming school:
Automated testing can be viewed as a trade-off between budget, time and quality.The effort invested in automated tests should result in at least an equivalent improvement in software quality.
There are Test Driven Development and Behaviour Driven Development type of testing.
Test Driven Development (TDD)
TDD is a set of tests that drive the development and make sure that NO CODE goes into production without associated tests.
TDD rules:
- You may not write production code until you have written a failing unit test
- You may not write more of a unit test than is sufficient to fail, and not compliling is failing
- You may not write more production code than is sufficient to pass the current failing test
The TDD Cycle (the Red, Green, Refactor cycle):
- We first write a failing test, represented in many testing tools by the color red.
- We then implement code to get the test to pass, represented by the color green.
- If necessary, we refactor the code, changing its form without changing its function.
Behaviour-Driven Development (BDD)
- BDD is based on TDD
- BDD is speficying how your application should work, rather than verifying that it works
- Its about implementing an application by describing its behavior from the perspective of its customer’s point of view
TDD vs BDD:
The difference is that one is called Behaviour Driven Development – and some people find that wording useful – and one (or two) is called (Acceptance) Test Driven Development – and some people find that wording useful in a different way.
-
Difference in language example:
- In TDD: assertEquals(count,5)
- In BDD: $(count).should_be(5)
-
Explaining differences between TDD vs BDD using the Sorting algoritm where using different types of algorithms to sort:
-
TDD: The unit test will change for each algorithm because you want to know as you doing the sort, its doing it correctly
-
BBD: its one set of test you need for all of these sorting algorithms
Testing for Rails:
There is a wide variety of different approaches and aids for testing in rails. Based on my research, here I am listing some of the most used testing tools by the rails community:
-
Test::Unit: Rails by default provides unit, functional and integration tests but its not the only way to test rails applications.
-
NullDB: A way to speed up testing by avoiding database use
-
Machinist: Blueprints to generate Active Record objects
Hole.blueprint do number 1 end (1..18).each {|n| Hole.make(:number =>n)}
-
Shoulda: An extension to Test::Unit with the idea of contexts ( contains additional helpers, macros and assertions)
-
Cucumber: *Good for making sure all these sort of high-level features and functionalities are covered
- Based on definition of scenarios within features (key words used in cucumber: Feature (In order, As a) Scenario(Given, When, Then)
-
Capybara: Makes it easy to simulate how a user interacts with your application capybara
-
Factory Girl:
- A replacement for fixtures (fixtures are sample of pre defined data to populate testing database runs).
-
It has a straightforward definition syntax, support for multiple build strategies(saved and unsaved instances, attribute bases, and stubbed objects), and support for multiple factories for the same class(user, admin_user, and so on), including factory inheritance.
-
factory_girl_rails provides rails integration for factory_girl. Setup steps:
- gem install factory_girl_rails
- Add factory_girl_rails to your gem file (gem ‘factory_girl_rails’)
- FYI: You need to ensure that factory_girls_rails is available in the development group. If its not, rails will generate standard yml files instead of factory files
-
RSpec:
- Its a BDD unit-testing framework for Ruby.
- It combines the general techniques and principles of TDD.
- spec provides the structure for writing executable examples of how your code should behave and an spec command with tools to constrain which examples get run and tailor the output.
- Its an idea about how software development should be managed by both business interests and technical insight and it assume the use of specialized software tools to support the development process(spec-rails is a testing framework for rails 3.x and 4x).
- Describe a step with a Describe, Context or It block that contains the business specification
Example of spec file:
describe Class do
before do
setup something
end
it "should return something" do
actual_result.should eq(expected_result)
end
end
Example of Rspec:
describe Player do
before(:each) do
@valid_attributes = {
:first_name => "value for first_name";
:last_name => "value for last_name";
:active => true
}
end
it "should create a new instance given valid attributes" do
Player.create!(@valid_attributes)
end
Code Example
- Model specs
class User
has_and_belongs_to_many :companies
validates :companies, presence: true, associated: true
validates :email, presence: true
validates :email, uniqueness: true
validates :password, presence: true
class << self
# Finds user by email
# Method does not case sensitive
def find_by_email(email)
where(email: /#{email}$/i).first
end
end
def first_company
companies.first
end
end
Model Specs – Example rspec model code
require 'spec_helper'
describe User do
describe 'associations' do
it { have_and_belong_to_many(:companies) }
end
describe 'validations' do
it { should validate_presence_of(:email) }
it { should validate_uniqueness_of(:email) }
it { should validate_presence_of(:password) }
it { should validate_presence_of(:companies) }
end
describe '.find_by_email' do
let!(:user) { create(:user, email: '[email protected]') }
it 'return user by email' do
User.find_by_email('[email protected]').should == user
end
it 'does not case sensitive' do
User.find_by_email('[email protected]').should == user
end
end
describe "#first_company" do
let(:first_company) { create(:company, name: 'first') }
let(:user) { create(:user, companies: [first_company] }
subject {user.first_company }
it 'should return the first company' do
should == first_company
end
end
-
Pending: “Unit vs Integration testing” (using car example)
-
References:
- http://rspec.info/
- https://github.com/thoughtbot/factory_girl
- https://github.com/thoughtbot/factory_girl_rails
- http://keithpitty.com/blog/tags/testing
- http://betterspecs.org/
- Code example: http://www.slideshare.net/TrietLeminh/basic-rspec-2
describe String do
subject { "gabriela" }
describe "#upcase" do
it "should return GABRIELA" do
subject.upcase.should == "GABRIELA"
end
end
describe "#include?" do
let(:included) { "a" }
let(:not_included) { "o" }
it "should return true if it contains string" do
subject.include?(included).should == true
# subject.should end_with("0")
# subject.end_with?.should == true
end
it "should return false if not included" do
subject.include?(not_included).should == false
end
end
describe "#include?" do
context "when it contains the string" do
let(:string) { "a" }
it "should return true" do
subject.include?(string).should == true
end
end
context "when it doens't contain the string" do
let(:string) { "o" }
it "should return false" do
subject.include?(string).should == false
end
end
end
end
Resource: https://gist.github.com/evagabriela/189517c3130f4cdeb04c