Friday, February 8, 2013

I Get Paid for Code That Works

I was recently enamored with using a test framework to test the application I  am developing.

I looked into using the Rack::Test framework to test my RESTful APIs.

It looked clean and minimal.  Looks are sometimes deceiving.

I created a very simple proof of concept.  

A service that returns the names of my kids.

The following scaffold command created the Rails app:

bundle exec rails generate scaffold Kid name:string

I entered  the names in the Rails Console:

Kid.create!(:name => 'Emma')
Kid.create!(:name => 'Kelly May')
Kid.create!(:name => 'Marty')


I tested the index action using my web browser





I created the Rack Test Test Case



require File.join(File.dirname(__FILE__), *%w[.. test_helper])

class KidsTest < ActiveSupport::TestCase
  include Rack::Test::Methods

  def app
    KidsController.action(:index)
  end

  def test_get
    get "/kids"
    assert_equal "Hello world", last_response.body
  end
end

# This would include the application's middleware,
# which you probably want as it includes sessions
# and cookies
class TestApplication < Test::Unit::TestCase
  include Rack::Test::Methods

  def app
    MyApplication
  end

  def test_get
    get "/kids"
    assert_equal "Hello world", last_response.body
  end
end




I ran the test




/Volumes/HoneyBadger1TB/Users/lex/.rbenv/versions/1.9.3-p194/bin/ruby -e $stdout.sync=true;$stderr.sync=true;load($0=ARGV.shift) -Itest /Volumes/HoneyBadger1TB/Users/lex/PROJECTS/racktest/test/rack/kids_test.rb
Testing started at 4:55 PM ...
Rack::File headers parameter replaces cache_control after Rack 1.5.

MiniTest framework was detected. It is a lightweight version of original Test::Unit framework.
RubyMine/IDEA Ruby plugin test runner requires 'minitest-reporters' (>= 0.5.0) for integration
with MiniTest framework (see http://www.jetbrains.com/ruby/webhelp/minitest.html).
Or you can use full-featured Test::Unit framework version, provided by
'test-unit' gem, otherwise default console tests reporter will be used instead.

        
Run options: 

# Running tests:

F

Finished tests in 0.031349s, 31.8989 tests/s, 31.8989 assertions/s.

  1) Failure:
test_get(KidsTest) [/Volumes/HoneyBadger1TB/Users/lex/PROJECTS/racktest/test/rack/kids_test.rb:12]:
<"[{\"created_at\":\"2013-02-08T14:23:57Z\",\"id\":1,\"name\":\"Emma\",\"updated_at\":\"2013-02-08T14:24:17Z\"},{\"created_at\":\"2013-02-08T14:25:40Z\",\"id\":2,\"name\":\"Kelly May\",\"updated_at\":\"2013-02-08T14:25:40Z\"},{\"created_at\":\"2013-02-08T14:25:57Z\",\"id\":3,\"name\":\"Marty\",\"updated_at\":\"2013-02-08T14:25:57Z\"}]"> expected but was
<"[]">.

1 tests, 1 assertions, 1 failures, 0 errors, 0 skips

Process finished with exit code 1




Conclusion


Perhaps I'm missing something here, but it looks like Rack Test is expecting me to mock out the data for its get command to retrieve the RESTful response.

I'm not interested in writing a lot of dummy code to test my real code.

There is great benefit to writing comprehensive and modular test code, e.g., code that tests the model layer (unit tests -- very valuable), code that tests APIs (api tests -- very valuable), but then when you start getting into functional, integration and regression testing, it's best to be selective.

With a team of developers, continuous integration testing is a must.

The more developers you have, the more comprehensive and modular your test suite should be.  As a developer, I don't want some other developer to be able to deliver code that breaks _my_ code.  I want the build to break and point at that other developer--not me--when their code change makes it look like _my_ code is broken.

So, with a team of developers, each developer is in a race to push their code that could possibly be affected by other developers _before_ the other developers have a chance to checkin their code.  The last guy to push their code must take time to perform the requisite code merge.

If you test too much or the tests are brittle, it'll be more of a cost than a benefit.

Tests are code that don't have test coverage.

All tests have costs.  Some tests have value.


Next Steps


Choosing the right tools for testing can save a lot of time.

For API testing, using simple rest-client to test in a test environment against real data makes a lot of sense to me.

Adding a sample_data method to return mock response, coded directly in the model, which can be exercised for time sensitive testing also makes a lot of sense to me.




References

http://guides.rubyonrails.org/testing.html
https://rubygems.org/gems/rest-client
http://lanyrd.com/2012/railsconf/srhwt/
http://stackoverflow.com/questions/6885572/complete-rails-json-api-example-with-rspec-tests
http://manning.com/katz/

Sponsor Ads


1 comment:



  1. I also agree with you ..... very useful information for us ...... keep it up thanks for this..........






    Application Development

    ReplyDelete