Sunday, November 30, 2008
Sometimes
Have a look at this interesting blog post from Dan Croak about questioning current testing methods.
Thursday, July 24, 2008
Remember to reload your associations in your tests
Save time by reloading your associations when using RSpec.
Just put a reload after your association call:
1 # your_object.rb
2 class YourObject < ActiveRecord::Base
3 def your_method
4 self.your_association << TestObject.new
5 end
6 end
7
8 # your_object_spec.rb
9 it "should test your_method" do
10 lambda { your_object.your_method }.should change(your_object.your_association, :size) # => no change, test fails....
11 end
12
Just put a reload after your association call:
1 # your_object_spec.rb
2 it "should test your_method" do
3 lambda { your_object.your_method }.should change(your_object.your_association.reload, :size) # => association reloads and the test succeeds
4 end
Tuesday, July 22, 2008
ordered method testing with rspec
Since I am learning RSpec for Rails I wonder how to write a test which tests the order of the methods called by my method. Now I found a solution which works. The answer is simple: should_receive takes a block which is called after the assertion of the should_receive ran.
Your code may look like this:
Looks kind of ugly but it works...
Your code may look like this:
1 # user.rb
2 def change_my_attributes(name,login,password)
3 self.name = name
4 self.login = login
5 self.password = password
6 save!
7 end
8
9 # user_spec.rb
10 it "should run my methods in #change_my_attributes in the correct order" do
11 @user = User.new
12 @user.should_receive(:name=) do
13 @user.should_receive(:login=) do
14 @user.should_receive(:password=) do
15 @user.should_receive(:save!)
16 end
17 end
18 end
19 @user.change_my_attributes('foo','bar','foobar')
20 end
Looks kind of ugly but it works...
Monday, July 14, 2008
test/unit, test/spec, RSpec, shoulda
Who has experience with two of these test frameworks, and can tell about this? Which one is better, and why?
Labels:
question,
request for comments,
test frameworks
Saturday, July 12, 2008
Keep your tests small
Keeping your tests small sounds a bit odd, but it's quite easy to get in a test flow and to write spaghetti tests, testing too much at once. Stay focussed on what to test, and just test this single aspect of your code!
1 # don't do this!This test is hard to read, since it tests three aspects at once. Even the dscription block is a bit ambiguous. The test is unfocused, and as a matter of result, in case your test contains an error itself, it's hard to debug. The following three tests are much better:
2 describe "A user's display name" do
3 it "should reflect the user's name" do
4 user = User.new(:login => 'alto')
5 user.display_name.should eql('alto')
6
7 user.firstname = 'Thorsten'
8 user.display_name.should eql('Thorsten')
9
10 user.lastname = 'Böttger'
11 user.display_name.should eql('Thorsten Böttger')
12 end
13 end
14
1 # much better
2 describe "A user's display name" do
3 before do
4 @user = User.new(:login => 'alto')
5 end
6 it "should equal the login name if no other name is given" do
7 @user.display_name.should eql('alto')
8 end
9 it "should equal his firstname if it is given" do
10 @user.firstname = 'Thorsten'
11 @user.display_name.should eql('Thorsten')
12 end
13 it "should equal his fullname if firstname and lastname are given" do
14 @user.firstname = 'Thorsten'
15 @user.lastname = 'Böttger'
16 @user.display_name.should eql('Thorsten Böttger')
17 end
18 end
19
Saturday, June 28, 2008
Hide external access behind a small facade for easy mocking
Imagine you have validation like this, where you call the youtube website to make sure the provided video id is valid:
Actually, this code fragment is a pain in the neck to test. If you hide the external access behind a small facade (or wrapper if you like) like this:
1 class Video < ActiveRecord::Base
2 def validate
3 response = Net::HTTP.start('youtube.com') { |http| http.head("/v/#{self.youtube_video_id}") }
4 unless response.is_a?(Net::HTTPOK)
5 errors.add(:youtube_video_id, "no valid Youtube Video ID")
6 end
7 end
8 end
9
1 class YouTubeit's much easier to test:
2 def self.video_id_valid?(video_id)
3 response = Net::HTTP.start('youtube.com') do |http|
4 http.head("/v/#{self.youtube_video_id}")
5 end
6 response.is_a?(:Net::HTTPOK)
7 end
8 end
9
10 class Video < ActiveRecord::Base
11 def validate
12 unless Youtube.video_id_valid?(self.youtube_video_id)
13 errors.add(:youtube_video_id, "no valid Youtube Video ID")
14 end
15 end
16 end
17
1 # video_spec.rb
2 describe Video, "validations" do
3 before(:each) do
4 @video = Video.new(:youtube_video_id => 'iY6VroKoB8E')
5 end
6 it "should succeed with correct youtube video id" do
7 Youtube.stub!(:video_id_valid?).and_return(true)
8 @video.should be_valid
9 end
10 it "should fail with incorrect youtube video id" do
11 Youtube.stub!(:video_id_valid?).and_return(false)
12 @video.should_not be_valid
13 end
14 end
15
Monday, June 9, 2008
Test first

There is a long history of postings and even books written about this topic. Most of the time it is called test-driven development (or design resp.) or behavior-driven development, what doesn't matter now. The important thing about it is that you do it first, before writing a single line of code.
Why should I do that?
Most important, it helps you to look at your application from a different point of view. You just concentrate on the desired behavior, and don't think about the how (you would do it), just the what (to do). Next, when writing the tests after your code, you simply test too much or too less, and are too close to the implementation details. And finally, it's best practice to write a test first for every bug you encounter, just to reproduce the error and make sure that it will never ever happen again!
Are there any problems?
One might say your tests are too integrative, meaning that you focus on more than the unit to test, and you probably and simply test too much. But I think it's just a matter of experience, and at the end you can optimize your tests just like the application code later on.
A simple example
You start by describing what your application, method or class should behave like. The user model in this case:
1 # user_spec.rb
2 describe "A user's display name" do
3
4 it "should equal his/her login if no other name is available"
5
6 it "should equal his/her full name if available"
7
8 end
9
What do we have here? First, at line 1 we defined a context for our test, using RSpec's describe block (have a look at RSpec documentation for details). Furthermore we have two behaviors (it-blocks), defining what we expect our system to behave like. Let's go a step further and fill these up a bit:
1 # user_spec.rb
2 describe "A user's display name" do
3 it "should equal his/her login name if no other is available" do
4 user = User.new(:login => 'dude')
5 user.display_name.should eql('dude')
6 end
7 it "should equal his/her full name if available" do
8 user = User.new(:login => 'dude', :name => 'Thorsten Böttger')
9 user.display_name.should eql('Thorsten Böttger')
10 end
11 end
12
At the very end, you write the application code, and fire up the tests to check, if it behaves
the way you wanted while writing the tests:
1 # user.rb
2 class User < ActiveRecord::Base
3 def display_name
4 name.blank? ? login : name
5 end
6 end
7
Saturday, June 7, 2008
Welcome
Welcome aboard this blog about best practices for testing Ruby on Rails applications. We are Jan Krutisch and Thorsten Böttger, two Rails hackers from Hamburg, Germany.
Labels:
best practices,
rails,
ruby on rails,
testing,
welcome
Subscribe to:
Posts (Atom)