Testing Legacy Rails Apps

0 %
100 %
Information about Testing Legacy Rails Apps

Published on May 19, 2007

Author: rabble

Source: slideshare.net

Description

Presentation at Rails Conf 2007 about adding tests to legacy ruby on rails applications.

Testing Legacy Rails Applications Evan ‘rabble’ Henshaw-Plath Yahoo! Brickhouse anarchogeek.com - testingrails.com presentation slides - slideshare.net/rabble

Do We Have Legacy Already? Yes, thousands of rails apps have been built and deployed over the last three years. Many of us included few or no tests. The test-less apps still need debugging, which should be done with tests.

Testing == Health Food? “We started the tests, but haven’t been updating them” “Who has time for tests?” “Testing means writing twice as much code.”

Testing == Debugging

no, really, it is

Starting

Don’t do it all at once

Get Rake Working brickhouse:~/code/legacy_testing rabble$ rake (in /Users/rabble/code/legacy_testing) /opt/local/bin/ruby -Ilib:test quot;/opt/local/lib/ruby/gems/1.8/gems/rake-0.7.2/lib/rake/rake_test_loader.rbquot; /opt/local/bin/ruby -Ilib:test quot;/opt/local/lib/ruby/gems/1.8/gems/rake-0.7.2/lib/rake/rake_test_loader.rbquot; #42000Unknown database 'legacy_testing_development' /opt/local/lib/ruby/gems/1.8/gems/activerecord-1.15.3/lib/active_record/vendor/mysql.rb:523:in `read' /opt/local/lib/ruby/gems/1.8/gems/activerecord-1.15.3/lib/active_record/vendor/mysql.rb:153:in `real_connect' /opt/local/lib/ruby/gems/1.8/gems/activerecord-1.15.3/lib/active_record/connection_adapters/ mysql_adapter.rb:389:in `connect' /opt/local/lib/ruby/gems/1.8/gems/activerecord-1.15.3/lib/active_record/connection_adapters/ mysql_adapter.rb:152:in `initialize'

Create your test db mysqladmin -uroot create railsapp_test

Use Migrations brickhouse:~/code/legacy_testing rabble$ rake db:migrate (in /Users/rabble/code/legacy_testing) == CreateArticles: migrating ==================== -- create_table(:articles) -> 0.2749s == CreateArticles: migrated (0.2764s) =============

Try Rake Again brickhouse:~/code/legacy_testing rabble$ rake (in /Users/rabble/code/legacy_testing) /opt/local/bin/ruby -Ilib:test quot;/opt/local/lib/ruby/gems/1.8/gems/rake-0.7.2/lib/rake/rake_test_loader.rbquot; quot;test/unit/ article_test.rbquot; Loaded suite /opt/local/lib/ruby/gems/1.8/gems/rake-0.7.2/lib/rake/rake_test_loader Started . Finished in 0.316844 seconds. 1 tests, 1 assertions, 0 failures, 0 errors /opt/local/bin/ruby -Ilib:test quot;/opt/local/lib/ruby/gems/1.8/gems/rake-0.7.2/lib/rake/rake_test_loader.rbquot; quot;test/ functional/blog_controller_test.rbquot; Loaded suite /opt/local/lib/ruby/gems/1.8/gems/rake-0.7.2/lib/rake/rake_test_loader Started . Finished in 0.243161 seconds. 1 tests, 1 assertions, 0 failures, 0 errors /opt/local/bin/ruby -Ilib:test quot;/opt/local/lib/ruby/gems/1.8/gems/rake-0.7.2/lib/rake/rake_test_loader.rbquot;

Scaffolding is Broken

Ok now we’re ready to get started

One Step At A Time

find a bug - write a test

refractor a method write a test

Treat Each Method As Box

Test One Thing At A Time

What Goes In? What Comes Out?

Running Tests rake & directly

Running Tests with rake rake test # Test all units and functionals rake test:functionals # Run the functional tests in test/functional rake test:integration # Run the integration tests in test/integration rake test:plugins # Run the plugin tests in vendor/plugins/**/test rake test:recent # Test recent changes rake test:uncommitted # Test changes since last checkin (svn only) rake test:units # Run the unit tests in test/unit

running tests directly Test::Unit automatic runner. Usage: blog_controller_test.rb [options] [-- untouched arguments] run them all ruby article_controller_test.rb give it a test name ruby article_controller_test.rb -n test_show try regular expressions ruby article_controller_test.rb -n /show/ get help: ruby --help

An Example def User.find_popular(n=20) sql = quot;select u.*, count(j.user_id) as popularity from users u, talks_users j where u.id = j.user_id group by j.user_id order by popularity desc limit #{n}quot; return User.find_by_sql(sql) end

An Example def User.find_popular(n=20) sql = quot;select u.*, count(j.user_id) as popularity from users u, talks_users j where u.id = j.user_id group by j.user_id order by popularity desc limit #{n}quot; return User.find_by_sql(sql) end def test_popular assert_nothing_raised { users = User.find_popular(2) } assert_equal 2, users.size, quot;find_popular should return two usersquot; assert users.first.popularity > users.last.popularity, quot;should sort popular usersquot; end $ ruby ./test/unit/user_test -n test_popular brickhouse:~/code/icalico/trunk/test/unit rabble$ ruby user_test.rb -n /popular/ Loaded suite user_test Started . Finished in 0.290563 seconds.

Refactor def self.find_popular(n=20) return conference.attendees.find(:all, :select => quot;users.*, count(talks_users.user_id) as popularityquot;, :joins => quot;LEFT JOIN talks_users on users.id = talks_users.user_idquot;, :group => quot;talks_users.user_idquot;, :order => 'popularity', :limit => n ) end $ ruby ./test/unit/user_test -n test_popular brickhouse:~/code/icalico/trunk/test/unit rabble$ ruby user_test.rb -n /popular/ Loaded suite user_test Started F Finished in 0.290563 seconds. 1) Failure: test_popular(UserTest) [user_test.rb:10]: Exception raised: Class: <NoMethodError> Message: <quot;You have a nil object when you didn't expect it!nThe error occured while evaluating nil.attendeesquot;> ---Backtrace--- /Users/rabble/code/icalico/trunk/config/../app/models/user.rb:35:in `find_popular' user_test.rb:10:in `test_popular' user_test.rb:10:in `test_popular' ---------------

Refactor def self.find_popular(n=20) return self.find(:all, :select => quot;users.*, count(talks_users.user_id) as popularityquot;, :conditions => [quot;users.conference_id = ? quot;, conference.id], :joins => quot;LEFT JOIN talks_users on users.id = talks_users.user_idquot;, :group => quot;talks_users.user_idquot;, :order => 'popularity', :limit => n ) end $ ruby ./test/unit/user_test -n test_popular brickhouse:~/code/icalico/trunk/test/unit rabble$ ruby user_test.rb -n /popular/ Loaded suite user_test Started . Finished in 0.290563 seconds.

build test from logs ./log/development.log Processing ArticlesController#show (for 0.0.0.0 at 2006-07-20 11:28:23) [GET] Session ID: Parameters: {quot;actionquot;=>quot;showquot;, quot;idquot;=>quot;2quot;, quot;controllerquot;=>quot;articlesquot;} Article Load (0.002371) SELECT * FROM articles LIMIT 1 Rendering within layouts/articles Rendering articles/show Article Columns (0.007194) SHOW FIELDS FROM articles Completed in 0.10423 (9 reqs/sec) | Rendering: 0.08501 (81%) | DB: 0.01022 (9%) | 200 OK [http://test.host/articles/show/1]

the functional test ./test/functional/article_controller_test.rb require File.dirname(__FILE__) + '/../test_helper' require 'articles_controller' # Re-raise errors caught by the controller. class ArticlesController def rescue_action(e) raise e end end class ArticlesControllerTest &lt; Test::Unit::TestCase def setup @controller = ArticlesController.new @request = ActionController::TestRequest.new @response = ActionController::TestResponse.new end # Replace this with your real tests. def test_truth assert true end end

get the params ./log/development.log Processing ArticlesController#show (for 0.0.0.0 at 2006-07-20 11:28:23) [GET] Session ID: Parameters: {quot;actionquot;=>quot;showquot;, quot;idquot;=>quot;2quot;, quot;controllerquot;=>quot;articlesquot;} Article Load (0.002371) SELECT * FROM articles LIMIT 1 Rendering within layouts/articles Rendering articles/show Article Columns (0.007194) SHOW FIELDS FROM articles Completed in 0.10423 (9 reqs/sec) | Rendering: 0.08501 (81%) | DB: 0.01022 (9%) | 200 OK [http://test.host/articles/show/1]

what to test? 1. Assert that the page action rendered and returned successful HTTP response code, i.e. 200. 2. Assert that the correct template was rendered. 3. Assert that action assigns a value to the @article variable. 4. Assert that the right @article object was loaded.

writing the test ./test/functional/article_controller_test.rb def test_show get :show, {quot;actionquot;=>quot;showquot;, quot;idquot;=>quot;2quot;, quot;controllerquot;=>quot;articlesquot;} #confirm that the http response was a 200 (i.e. success) assert_response :success #confirm that the correct template was used for this action assert_template 'articles/show' #confirm that the variable @article was assigned a value assert assigns( :article ) #confirm that the @article object loaded has the id we want assert_equal 2, assigns( :article ).id end

running the test rabble:~/code/tblog/test/functional evan$ ruby articles_controller_test.rb -n test_show Loaded suite articles_controller_test Started F Finished in 0.625045 seconds. 1) Failure: test_show(ArticlesControllerTest) [articles_controller_test.rb:27]: <2> expected but was <1>. 1 tests, 4 assertions, 1 failures, 0 errors

fix the bug The old code app/controller/articles_controller.rb: def show @article = Article.find(:first) end The fix is easy, we update it so the Article.find method app/controller/articles_controller.rb: def show @article = Article.find(params[:id]) end

running the test rabble:~/code/tblog/test/functional evan$ ruby articles_controller_test.rb -n test_show Loaded suite articles_controller_test Started . Finished in 0.426828 seconds. 1 tests, 3 assertions, 0 failures, 0 errors

test coverage

rake stats brickhouse:~/code/icalico/trunk rabble$ rake stats (in /Users/rabble/code/icalico/trunk) +----------------------+-------+-------+---------+---------+-----+-------+ | Name | Lines | LOC | Classes | Methods | M/C | LOC/M | +----------------------+-------+-------+---------+---------+-----+-------+ | Helpers | 107 | 81 | 0| 9| 0| 7| | Controllers | 517 | 390 | 10 | 52 | 5| 5| | Components | 0| 0| 0| 0| 0| 0| | Functional tests | 416 | 299 | 18 | 58 | 3| 3| | Models | 344 | 250 | 8| 37 | 4| 4| | Unit tests | 217 | 159 | 9| 25 | 2| 4| | Libraries | 257 | 162 | 4| 32 | 8| 3| | Integration tests | 0| 0| 0| 0| 0| 0| +----------------------+-------+-------+---------+---------+-----+-------+ | Total | 1858 | 1341 | 49 | 213 | 4| 4| +----------------------+-------+-------+---------+---------+-----+-------+ Code LOC: 883 Test LOC: 458 Code to Test Ratio: 1:0.5

rcov test coverage

rcov test coverage what needs to be tested?

rcov test coverage what gets executed when you run tests

rcov test coverage summary

rcov test coverage per file reports

Heckle more later on this

autotest because sometimes our tests can run themselves

autotest

Continuous Integration

You can go deeper

Fixtures Ugliness ar_fixtures use mocks fixture senarios

zentest

focus on the bugs

Flickr Photos •http://flickr.com/photos/maguisso/247357791/ •http://flickr.com/photos/jurvetson/482054617/ •http://flickr.com/photos/candiedwomanire/352027/ •http://flickr.com/photos/mr_fabulous/481255392/ •http://flickr.com/photos/dharmasphere/125138024/ •http://flickr.com/photos/misshaley/450106803/ •http://flickr.com/photos/19684903@N00/317182464/ •http://flickr.com/photos/planeta/349424552/ •http://flickr.com/photos/izarbeltza/411729344/ •http://flickr.com/photos/mikedefiant/447379072/ •http://flickr.com/photos/fofurasfelinas/74553343/ •http://flickr.com/photos/thomashawk/422057690/ •http://flickr.com/photos/cesarcabrera/396501977/ •http://flickr.com/photos/thearchigeek/418967228/ •http://flickr.com/photos/thomashawk/476897084/ •http://flickr.com/photos/gini/123489837/ •http://flickr.com/photos/neilw/233087821/ •http://flickr.com/photos/good_day/450356635/ •http://flickr.com/photos/ronwired/424730482/ •http://flickr.com/photos/monster/148765721/ •http://flickr.com/photos/monkeyc/200815386/ •http://flickr.com/photos/charlesfred/243202440 •http://flickr.com/photos/dramaqueennorma/191063346/ •http://flickr.com/photos/incognita_mod/433543605/ •http://flickr.com/photos/filicudi/272592045/ •http://flickr.com/photos/martinlabar/163107859/ •http://flickr.com/photos/gaspi/6281982/ •http://flickr.com/photos/iboy_daniel/98784857/ •http://flickr.com/photos/silvia31163/199478324/ •http://flickr.com/photos/tjt195/68790873/ •http://flickr.com/photos/nidriel/103210579/ •http://flickr.com/photos/charlietakesphotos/25951293/ •http://flickr.com/photos/leia/29147578/ •http://flickr.com/photos/90361640@N00/282104656/

Get Your Feet Wet Next: Evan ‘rabble’ Henshaw-Plath Yahoo! Brickhouse anarchogeek.com Heckle testingrails.com slides: slideshare.net/rabble

Add a comment

Related presentations

Related pages

GitHub - RailsApps/rails_apps_testing: Set up a testing ...

rails_apps_testing - Set up a testing framework for a Rails application.
Read more

Docker on a Legacy Rails App - Createk.io

Docker on a Legacy Rails App ... (for capybara webkit testing). The apps gems are baked-in the image which improves performance for first-time pulls and ...
Read more

A Guide to Testing Rails Applications — Ruby on Rails Guides

A Guide to Testing Rails Applications. This guide covers built-in mechanisms in Rails for testing your application. After reading this guide, you will know:
Read more

GitHub - paulfioravanti/legacy_app: Example Ruby 1.8.7 and ...

legacy_app - Example Ruby 1.8.7 and Rails 2.3 project to use as an exercise in upgrading to Ruby 1.9 and Rails 3.2.12
Read more

Upgrade your legacy Rails app

Extend the life of your outdated Ruby on Rails application. Now updating Rails 1, Rails 2, and Rails 3 to Rails 4.2. Don't rebuild; Upgrade.
Read more

Our Fight Against Super Bad Patterns in Legacy Rails Apps ...

Our Fight Against Super Bad Patterns in Legacy Rails Apps - RedDotRubyConf 2016 Tweet. Published on: Sunday, 26 June 2016.
Read more

testing - What are the first steps in hardening a legacy ...

There is a production system that has been running for many years, first as a PHP application, then as a hybrid with Rails, and now completely in Rails. It ...
Read more

How We Test Rails Applications - robots.thoughtbot.com

Testing Rails Book This was just an overview of how we test Rails applications. Check out our new book, ... and it includes an example app. ...
Read more

Ruby on Rails Guides: Performance Testing Rails Applications

Performance Testing Rails Applications. This guide covers the various ways of performance testing a Ruby on Rails application. By referring to this guide ...
Read more