Testing fundamentals
and
Introduction to Rspec
@h6165
The Fundamentals
The fundamentals: why test?
- Verification : Does this feature work?
- Spotting regression: Something broke something else
- Specification: The machine should work this way
- Documentation: Test describes how it should behave
-
Developer feedback:
- What I thought and what client wanted are different
- What I thought will not work
- Code design: Decoupling, cleaner interfaces, better OOP
The fundamentals: why test?
- Manual tests are the default solution to the problem
- Is also important, and unavoidable (UI/aesthetics)
- Easy to get started
-
Economical:
- ManualTester.price < Developer.price (generally)
Manual Tests
Semi automated tests
- Partially automated, needs some human involvement.
- Record and playback / Export and compare
- Not as repeatable as fully automated tests
The fundamentals: who writes the tests?
-
The developer
-
Testers/QA should write tests is an outdated idea, not practiced in Ruby world
The fundamentals: when to start?
When to start testing
-
As early as possible
- No tests are fine for very few situations, like prototype level or experimental projects
When to absolutely start testing
-
When the following signs show-up:
-
Regressions
-
Implementation slowness
-
Poor quality in general
-
Developer stress
-
The fundamentals: TDD
-
Test first, then code
- Needs specifications beforehand, as examples
- Ideal when specs are available (requirements)
- Leads to good design of code
- This talk/workshop is not about TDD
- This may be a stepping stone towards TDD
The fundamentals: Test environment
-
Rails comes with a test environment.
-
The idea is: the database should be separate
-
And some settings/config/gems should also be separate
-
Test scripts are programs written as part of the same code base
-
The scripts are executed using a test runner
-
Test scripts contain a bunch of test-cases
-
Every test-case undergoes a setup and a teardown phase
-
Data creation/setup needed for the test-case happens in the setup-phase
-
Teardown is for cleanup, deletes all data created by the test
-
(Ideally) each test-case runs in complete isolation, and should not be dependent on any other tests
The fundamentals: Minitest and RSpec
-
Rails ships with the MiniTest test framework. RSpec is a popular alternative
-
All Rails project get MiniTest by default, and can be replaced with RSpec
-
The default data creation technique in Rails is fixtures, while the popular one is factories.
-
The difference has been a subject of much debate
-
We will cover RSpec for this workshop. Switching between the two is not very difficult after knowing the fundamentals
The fundamentals: TDD controversy
-
There is also a debate over whether TDD is the correct way to approach software development
-
Rails creator David H Hansen has written articles opposing, and there have been several in-depth arguments from both sides
-
It is worth looking into the entire discussion before arriving at a decision
RSpec Introduction
Rspec introduction
- It is a test framework and a test runner
- We write test-cases using Rspec recommended syntax
- For verification, we use Rspec provided assertion methods
- We create data on our own (or using factories or fixtures) – Rspec has no involvement there
- RSpec gives a mocking framework too
Rspec introduction: the test case
## Code under test:
def add(a, b)
a + b
end
## The test
RSpec.describe 'add' do ## mention what is being tested
it 'should give 5 for 2 and 3' do ## The test case
c = add(2, 3) ## Invoke the code
expect(c).to eq(5) ## Verify the result
end
end
Rspec introduction: primary syntax
- There are many more methods and concepts, but this is enough to get started
it:
Holds the test case
expect..to..eq
The assertion statement. Does the verification
describe
Wraps the test cases, and declares what is being tested
Rspec introduction: running the tests
- Just one necessity: code under test should be loaded (require) before the describe block starts
-
The commend to run the test:
- rspec test_file.rb
Rspec Introduction: samples-1
- The above code can be placed in a file, and be run using the rpsec command.
- Will work if rspec gem is installed
## Tautology
require 'rspec'
RSpec.describe 'the truth' do
it 'should be true' do
expect(true).to eq(true)
end
it 'should not be false' do
expect(true).to_not eq(false)
end
end
## rspec sample1.rb
Rspec Introduction: samples-2
## Addition
def add(a, b)
a + b
end
## The test
require 'rspec'
RSpec.describe 'add' do
it 'should give 5 for 2 and 3' do
c = add(2, 3)
expect(c).to eq(5)
end
end
## rspec sample2.rb
Rspec Introduction: samples-3
## prime_number.rb
class PrimeNumber
def self.is_it?(num)
(2...num).each { |x| return false if num % x == 0 }
true
end
end
## prime_number_spec.rb
require 'rspec'
require File.expand_path('../prime_number.rb', __FILE__)
RSpec.describe 'PrimeNumber' do
describe 'is_it?' do
it 'should be true for 5' do
expect(PrimeNumber.is_it?(5)).to eq(true)
end
it 'should be false for 77' do
expect(PrimeNumber.is_it?(77)).to eq(true)
end
end
end
RSpec: common conventions
- Test code is kept in the spec directory
- There is generally a spec_helper.rb file that loads the necessary code and any plugins or even configs
- The .rspec file contains some config too
Introduction to Rspec
By Abhishek Yadav
Introduction to Rspec
- 1,202