web tech: lecture 5
TRANSCRIPT
SULEYMAN DEMIREL UNIVERSITY : ENGINEERING FACULTY : © ARDAK SHALKARBAYULY
Lecture 5RSpec testing,
SULEYMAN DEMIREL UNIVERSITY : ENGINEERING FACULTY : © ARDAK SHALKARBAYULY
Automated testing
Testing is a checking if your code is right
Every developer actually checks his project for
outputting correct values for different values.
Since testing is done many times and many
operations are repeated over a time, it is needed to
be automated
SULEYMAN DEMIREL UNIVERSITY : ENGINEERING FACULTY : © ARDAK SHALKARBAYULY
TDD - Test Driven
Development
Development where you first write tests and then
write code for them.
It is good for following cases:
Developers better understand what to do
It can be used as documentation
RSpec on Rails(Engineering Software as a Service §8.2)
Armando Fox
© 2012 Armando Fox & David Patterson
Licensed under Creative Commons Attribution-
NonCommercial-ShareAlike 3.0 Unported
License
SULEYMAN DEMIREL UNIVERSITY : ENGINEERING FACULTY : © ARDAK SHALKARBAYULY
RSpec
RSpec is a library to do automatic testing
SULEYMAN DEMIREL UNIVERSITY : ENGINEERING FACULTY : © ARDAK SHALKARBAYULY
RSpec usage
It’s tests are inside spec folder
To use in project: write in Gemfilegem 'rspec-rails'
rails generate rspec:install
run rake db:migrate
then run rake db:test:prepare
Last command prepares test database for testing
then run rspec
RSpec, a Domain-Specific
Language for testing
• RSpec tests (specs) inhabit spec directory
rails generate rspec:install creates
structure
• Unit tests (model, helpers)
• Functional tests (controllers)
• Integration tests (views)?
app/models/*.rb spec/models/*_spec.rb
app/controllers/
*_controller.rb
spec/controllers/
*_controller_spec.rb
app/views/*/*.html.haml (use Cucumber!)
The TDD Cycle:
Red–Green–Refactor(Engineering Software as a Service §8.3)
Armando Fox
© 2013 Armando Fox & David Patterson, all rights reserved
Test-First development
• Think about one thing the code should do
• Capture that thought in a test, which fails
• Write the simplest possible code that lets the
test pass
• Refactor: DRY out commonality w/other tests
• Continue with next thing code should do
Red – Green – Refactor
Aim for “always have working code”
How to test something “in
isolation” if it has dependencies
that would affect test?
The Code You Wish You Had
What should the controller method do that
receives the search form?
1.it should call a method that will search
TMDb for specified movie
2.if match found: it should select (new)
“Search Results” view to display match
3.If no match found: it should redirect to RP
home page with message
TDD for the Controller action:
Setup
• Add a route to config/routes.rb# Route that posts 'Search TMDb' form
post '/movies/search_tmdb'
– Convention over configuration will map this to MoviesController#search_tmdb
• Create an empty view:touch app/views/movies/search_tmdb.html.haml
• Replace fake “hardwired” method in movies_controller.rb with empty method:def search_tmdb
end
What model method?
• Calling TMDb is responsibility of the model... but
no model method exists to do this yet!
• No problem...we’ll use a seam to test the code we
wish we had (“CWWWH”), Movie.find_in_tmdb
• Game plan:
– Simulate POSTing search form to controller action.
– Check that controller action tries to call Movie.find_in_tmdb
with data from submitted form.
– The test will fail (red), because the (empty) controller
method doesn’t call find_in_tmdb.
– Fix controller action to make green.
http://pastebin.com/zKnw
phQZ
Optional!
Test techniques we know
obj.should_receive(a).with(b)
Should & Should-not
• Matcher applies test to receiver of should
count.should == 5` Syntactic sugar for
count.should.==(5)
5.should(be.<(7)) be creates a lambda that tests the
predicate expression
5.should be < 7 Syntactic sugar allowed
5.should be_odd Use method_missing to call odd?
on 5
result.should include(elt) calls #include?, which usually gets
handled by Enumerable
republican.should
cooperate_with(democrat)
calls programmer’s custom
matcher #cooperate_with (and
probably fails)
result.should render_template('search_tmdb')
SULEYMAN DEMIREL UNIVERSITY : ENGINEERING FACULTY : © ARDAK SHALKARBAYULY
spec/model/person_spec.rb
This file tests model Person, the line starting with it
is one test, text next to it is name of test, inside
functionrequire ‘spec_helper’
describe Person do
it ‘is invalid without name’ do
Person.create.should_not be_valid
end
end
SULEYMAN DEMIREL UNIVERSITY : ENGINEERING FACULTY : © ARDAK SHALKARBAYULY
should
should or should_not are next to object you want to
test
after should or should_not you can write:
== equals
be_valid if model is valid
have_text
redirect_tohttp://rspec.rubyforge.org/rspec-rails/1.1.12/classes/Spec/Rails/Matchers.html
SULEYMAN DEMIREL UNIVERSITY : ENGINEERING FACULTY : © ARDAK SHALKARBAYULY
Associationsbasic
SULEYMAN DEMIREL UNIVERSITY : ENGINEERING FACULTY : © ARDAK SHALKARBAYULY
Problem
We have two tables: Students and Group
Each group contains many students, so in students
table it has foreign key to group table.
So table students: name, surname, group_id
and table group: title
SULEYMAN DEMIREL UNIVERSITY : ENGINEERING FACULTY : © ARDAK SHALKARBAYULY
Dumb way #1:
Creating model and migrating
rails generate model Group title:string
rails generate model Student name:string
surname:string group_id:integer
rake db:migrate
SULEYMAN DEMIREL UNIVERSITY : ENGINEERING FACULTY : © ARDAK SHALKARBAYULY
Dumb way #1:
show all students of group #1
gr = Group.find(1)
studs = Student.all.where(group_id: gr.id)
This code is not beautiful, because it would be
better to find all students of group from object
SULEYMAN DEMIREL UNIVERSITY : ENGINEERING FACULTY : © ARDAK SHALKARBAYULY
has_many and belongs
add line has_many :students to Group model
and line belongs_to :group to Student model
Note: has_many is in plural form and belongs_to in
singular form
Now you can use:
gr = Group.find(1)
gr.students
Which will show all students of group with id 1
SULEYMAN DEMIREL UNIVERSITY : ENGINEERING FACULTY : © ARDAK SHALKARBAYULY
How it works
When you add belongs_to field to Student model, it
understands that foreign_key should be called
group_id, and works with it
SULEYMAN DEMIREL UNIVERSITY : ENGINEERING FACULTY : © ARDAK SHALKARBAYULY
Simplifying
Instead of rails generate model Student name:string group_id:integer
it’s better to userails generate model Student name:string group:references
Two commands create same database tables, but
second command automatically adds belongs_to
to Student table
SULEYMAN DEMIREL UNIVERSITY : ENGINEERING FACULTY : © ARDAK SHALKARBAYULY
Working through associations
grr = Group.find(1)
grr.students.create(:name=>”John”)
grr.students<<Student.create(:name=>”John”)
grr.students[2].name
SULEYMAN DEMIREL UNIVERSITY : ENGINEERING FACULTY : © ARDAK SHALKARBAYULY
has_one with different name
has_one :capital, :class_name=>”City”, foreign_key=>”capital_id”