Posts

Showing posts with the label RSpec

Iteration Zero

I spent the week doing an iteration zero for new project. The idea behind iteration zero is to get the development environment as automated as possible so developers can spend their time coding when the real development begins. So here's what we did: 1. Set up new git repository We use GitHub so that only took a few minutes. 2. Make new Rails app Again, just a few minutes 3. Set up geminstaller and basic gems (HAML etc.) Geminstaller installs gems needed by the project and makes sure they are there before starting the app. This functionality has been pulled into modern versions of Rails now, but I've found it a little wonky and I'm working with a former Pivotal Labs guy who just loves the Pivotal stuff (don't even get him started on Tracker vs Mingle ). 4. Set up developer tests. We looked into Shoulda , but ultimately went with RSpec (although we may use the Shoulda macros to test ActiveRecord) because most of the criticisms of RSpec are th...

Smells of Testing (signs your tests are bad)

Image
I spent the weekend at Citcon (Continuous Integration and Testing Conference) in Minneapolis. Citcon (which is pronounced Kitcon -- because it sounds cooler) is an open spaces conference which means that there are no scheduled talks. The people who show up propose ideas and then they vote on what they want to see. It sounds like it would never work but it actually works very well. For instance, Toby Tripp proposed a session on testing smells and it got enough votes to get a session but when I showed up there were only 6 people. Which kinda bummed me out until we started talking, then I realized that we had exactly the right 6 people and another 20, 50, or 100 half interested dudes typing away on their computers really wouldn't have added to the talk. As it was the talk was intimate and to the point. We came up with the following smells (a smell is a sign that something might be wrong -- Fowler used this metaphor to great effect in his seminal book " Refactoring ")...

When Your Mocks Burst into Flames

So yesterday Leah and I were working on SudokuScanner -- a cool little site that will, when it's released, allow you to upload images of Sudoku boards and get a solution. All of a sudden, our mocks and stubs went totally batshit. One minute she and I were happily writing some tests, making them pass, refactoring, checking in, etc... and then, we got a bunch of failures. OK, no problem -- we must have busted something with our latest change. The failure was a mock expectations error: UserMailer expected to receive a call to deliver_activation but did not receive it. So we went over to the failing spec and... There was no expectation on UserMailer anywhere in the spec. That's bad. Ran the spec by itself and it passes. Yep - not so good. Reverse the order that the specs run in (spec --reverse) and a different number of specs fail, but still with the same expectation failure. And of course these new specs all pass on their own. And have no reference to UserMailer anywher...

Sprinkle Some Integration Tests into a Mock Heavy Test Suite

I like mocks and stubs and I use them liberally in my tests. This practice, however, is not without danger: If my models, views, and controllers are all tested in isolation then how will I know if a model change busts a controller or a view? Here's something I like to drop in at the end of every controller spec: 1 2 3 4 5 6 7 8 9 10 11 12 describe JerkStoreController , " with views integrated and real objects " do integrate_views it " should render the page without blowing up " do store = JerkStore .create!( :name => " Costanza's house of bargins " ) store.products << Jerk .create!( :name => " Puddy " ) << Jerk .create!( :name => " Newman " ) << Jerk .create!( :name => " Steinbrenner " ) post :show , :id => store.id end end Not a mock or a stub as far as the eye can see and I'm even integrating views. No...

If you use Mocha and RSpec then read this

I like RSpec, but I'm not a huge fan of it's built in mocking framework. So, when I have the choice, I swap it out for Mocha. However, I really miss mock_model. If you haven't used it, mock_model is an RSpec method where you pass in an ActiveRecord object and it stubs out a whole bunch AR magic so you don't have to. This is crazy useful when testing controllers because when you controller has a line like this: redirect_to(@model) I don't want to dig through a ton of Rails code to figure out what I need to stub on this model, I just want it to work. But I just found out that Mislav Marohnić has written a plugin that implements mock_model for Mocha -- so now I can get the best of both worlds. You can find it here: http://github.com/mislav/rspec-rails-mocha Thanks Mislav.

Disconnecting RSpec from the Database

Recently I spent some time away from RSpec and I did miss it, but one thing especially liked about the testing framework I lived in for 10 months was that it had two ways to test anything you liked: One that hit the database and one that did not. We used UnitRecord to disconnect unit tests from the database (I should mention that we defined unit tests as tests that didn't hit the db and functional tests as those that did). So the vast majority of our tests didn't really need to hit the db and ran very fast. Sometimes we wanted or needed to hit the db and we did (only occasionally in model tests, more often in controller tests, and we kept logic out of the view and only tested views at the Selenium level). It was pretty cool and I'd like to thank the team who set it up before I got there. There's been a lot of talk about whether model, view, or controller tests should hit the db but I've found that there's enough exceptions that it's worth just saying that...

Saving in TextMate

So today, for something like the fifth time, I sat down in front of a TextMate installation that didn't have saving set up the way I like it: Auto save on loss of focus and when running a test (or spec). And, for the fifth time, I had to dig around the internet for the answer. So, as a public service to my future self: Save files when focus is lost: http://macromates.com/textmate/manual/saving_files TextMate --> Preferences --> Advanced --> Saving Save all files when running a test (or spec): http://macromates.com/textmate/manual/commands for specs: Bundles --> Bundle Editor --> Edit Commands --> Rspec --> Run Single Example Bundles --> Bundle Editor --> Edit Commands --> Rspec --> Run Examples for tests: Bundles --> Bundle Editor --> Edit Commands --> Ruby --> Run Bundles --> Bundle Editor --> Edit Commands --> Rspec --> Run Focused Unit Test Change the save drop down to "All Files in Project" Hope this helps, f...

Dead Simple Rails Metrics with metric_fu

Image
Every time I create a new rails project I usually put off writing tasks to analyze the code's quality 'cause it takes time and time is, you know, finite. So I've decided to extract some code into a rails plugin which I call metric_fu. It's a bunch of rake tasks that produce reports on code coverage (using Rcov ), cyclomatic complexity (using Saikuro ), flog scores (using Flog ), and rails stats (using 'rake stats'). It knows if it's being run inside a CruiseControl.rb build and puts the output in the Custom Build Artifacts folder so when you view a build you see this: The coverage report is your standard rcov report: Flog output is thrown into an html file: At the end metric_fu calculates the average flog score per method: You might want to check out my previous posts on what to do with a Flog report: The Method Hit List and When You Should Ignore Metrics Saikuro's output is the same as always: (I changed the warning and error levels for this pic -...

A Small Rails Site and Why You Should Build One

Image
The other day I was showing Rails off to a friend of mine who wanted to know what all the fuss was about and I realized a shocking thing: I was horrible at starting a Rails site. Why? Because for the last year or so I've been working on large, established Rails codebases. Which is kinda cool as it shows how far Rails has come, but it sucks because one of the very cool things about Rails is how much you can do in a short amount of time. So I resolved to create and deploy a small site as a way to exercise some atrophied muscles and have some good old fun with Ruby and Rails. My father, Leslie Scruggs, is a sculptor and I had written him a pure html site back in 1999. And he maintained it editing the raw html files, creating his own thumbnails, and uploading via ftp. Not the easiest of tasks for a man in his 60's. So I created lesliescruggs.com which has an admin section so he can upload pics and get them resized and thumbnailed with 10% of the effort. Of course I us...

RSpec on Rails: Models

In my last post I talked about using RSpec without Rails, but since just about all my Ruby programming involves Rails, I should probably get into how to specify Rails code. RSpec on Rails: Models So if you're new to RSpec and you want to get started quickly, head on over to rspec.rubyforge.org , get RSpec, Spec::Rails and then, after you've created a new Rails project and rspec-ed it (all detailed on the website) you can run: ruby script/generate rspec_scaffold person name:string phone_number:integer cash:decimal Which will get you a bunch of stuff to play with. Of you'll need to set up your database.yml and run rake db:migrate if you want thing to work. Fire up your favorite IDE and find the person_spec.rb and you should see something like: require File.dirname(__FILE__) + '/../spec_helper' describe Person do before(:each) do @person = Person.new end it "should be valid" do @person.should be_valid end end Not the world's mos...

RSpec without Rails

I'm going to try and turn my recent presentation on RSpec into a series of blog posts -- This being the first. Before I get on with it I would like to thank the Houston Ruby and Rails Users Group for having me. They asked some pretty insightful questions and were generally a great audience. I'd also like to thank ThoughtWorks for paying for my flight, rental car, and lost billable hours so I could do this presentation. RSpec without Rails So in order to show you how RSpec works, I'm going to start with specifying a class that deals with string case like so: require File.dirname(__FILE__) + '/../spec_helper' require 'string_caser' describe StringCaser do it "should upcase a string" do caser = StringCaser.new("A String") caser.upcase.should == "A STRING" end end After requiring a spec_helper and the file I intend to spec, I set up a 'describe' block. Inside the block there is a single spec (or example) which is als...

RSpec Resources

Later this evening I'm giving a talk on RSpec at the Houston Ruby and Rails Group. In case somebody misses a link, I'm posting them here: RSpec's homepage: rspec.rubyforge.org RSpec Users Mailing list: rubyforge.org/mailman/listinfo/rspec-users David Chelimsky's Blog: blog.davidchelimsky.net If you install RSpec as a plugin to your Rails project, then look inside: vendor/plugin/rspec/examples for some nice spec examples Once you've got RSpec and RSpec on Rails installed in your project, running: ruby script/generate rspec_scaffold person name:string phone_number:integer cash:decimal from the base of your project will get you a bunch of generated specs to look at and play with.

I'm Presenting on RSpec in Houston

I've been invited to give a presentation on RSpec at the Houston Area Ruby and Rails User Group on Monday August 6th -- and I'm pretty excited to do it. It'll be a nice opportunity to organize my thoughts and lessons learned after using RSpec on my last two projects. I'll be talking about the why and the how of RSpec (focusing mostly on the how), specifically as it applies to testing Rails apps. Watch this space for the blogization of this presentation.

First Day of Rails Conf 2007

Finished the first day of Rails Conf and here are my impressions: DHH's keynote: Lets celebrate what we have. Blah blah blah. Rails has come a long way. Yadda yadda yadda. Here's a sneak preview of what ActiveResource is going to be like in Rails 2.0. Ooooh, Aaaah. Actually the ActiveResource stuff was pretty cool. With a little bit of setup you can have one controller method serve up xml and text and html and all sorts of stuff. All RESTful style of course. And the debugger will be back (broken when someone fixed a bug in Ruby 1.85) and it will be a real debugger. When will 2.0 be out? He didn't say. Go use edge if you dare. Bob Martin's Clean Code Presentation: On the one hand, this is a lot of stuff I've heard before (I hung around Object Mentor at the start of my career), but Uncle Bob is such a good speaker he got me all fired up again about TDD, Red Green Refactor, and incremental steps. There was this point where a slide was clearly missing from th...

Stubbing/Mocking a Partial Within a Partial with RSpec

So in a previous post I complained about not being able to mock/stub a partial from within a partial, but with Peter Ryan and Mike Ward's help we got it all figured out. Normally in your test(spec) you call a partial like this: render :partial => 'partial_name', locals => {:page_variable => mock_page_variable } But if you want to intercept all or some calls to render with partial, them you can't do that. But what you can do is call a partial like so: render '_partial_name' If you need some locals you can stub them out like so: @controller.template.stub!(:page_variable). and_return(mock_page_variable) render '_partial_name' So if I wanted to stub out all calls to render, and assert that the string "Blargh" appears on the page, it would look a little something like this: @controller.template.stub!(:render) @controller.template.stub!(:page_variable). and_return(mock_page_variable) render '_partial_n...

Using OpenStruct to Enhance Your Mocks

So I use RSpec's built in mocking framework for my mocking/stubbing and it works quite well. I sent up a mock like so: mock_active_record_instance = mock("give it a name here, but probably a better one than this") and put some expectations on it like so: mock_active_record_instance.should_receive(:id).and_return(1) but some calls to the mock I don't care about so I can stub them out like so: mock_active_record_instance.stub!(:name). and_return("Arthur, King of the Britons") If I don't need it to return anything I can leave off the and_return and it will return nil. But it's tedious to do that. Lately I tend to use OpenStructs as my mocks like so: mock_active_record_instance = OpenStruct.new mock_active_record_instance.should_receive(:id).and_return(1) Now here's what's cool about that: My spec(test) will fail if the expectation of a call to id isn't met, but any other calls will be ignored (and nil returned). If I had made mock_a...

Mocking/Stubbing partials and helper methods in RSpec view specs

In my previous post I whined about not knowing how to mock/stub partials and helper methods in RSpec view specs. Now I have the answer and I’d like to thank the RSpec users mailing list and David Chelimsky for taking my phone call. In short, it’s all about @controller.template @controller.template.stub!(:a_helper_method).and_return(true) Stubs out the appropriately named a_helper_method and returns true. You can mock it out also like so: @controller.template.should_receive(:a_helper_method). at_least(:once).and_return(true) Which is like the stub except that it checks to see that a_helper_method was called at least once For partials you do this: @controller.template.should_receive(:render). with(:partial => 'form', :locals => {:cookie => mock_cookie}) Which checks to make sure the partial _form.rhtml is rendered and that the view attempted to pass mock_cookie in as a local. Since I didn’t specify a return it will return nil and I don’t have to worry about what’s...

What I want from view specs

I got an email today from a friend asking me about specifying views in RSpec in which he admitted he hadn’t done it much and first reaction was “I know what you mean!” Because it’s hard to spec views when you’re not hitting the database. You have to mock or stub out so many calls to your object just to get at the one or two lines you want to spec. And then I realized why I hate specifying views so much: It’s exactly like specifying a huge method. There’s all this stuff going on and you only care about one little bit and so you end up with 10 lines of mocking/stubbing to get to 3 lines of what you really want to say. Now with a ginormous method I have the option of pulling out little pieces of functionality into smaller methods and going straight at them. Then I can stub out those smaller methods when I’m specifying the big one. I can do this a little by creating a bunch of partials and specifying them individually, but when I want to spec the parent of all those partials I need...

Wrapping a Context in a Context (in RSpec)

A few days ago I blogged about solving a sticky problem by overwriting the “new” method on an ActiveRecord object inside a test (spec). Something I should have mentioned is that this is dangerous because if another spec (test) tries to call new and gets executed after the dangerous spec/test is run, then of course it won’t have the original new method. And it’s a very hard error to track down unless you know it’s been redefined. The solution to this, should you need to do it (and you probably won’t – any good mocking framework will probably do what you want), is to wrap a context around all the contexts that need it and use context_setup like this: context 'When the situation demands it' do context_setup do Class SomeObject def some_method_to_overwrite #do whatever I want -- Bwaa ha ha! end end end context 'Some context' do #specs go here end context 'Some other context' do #more specs go here end end After it ...

Rcov/RSpec problem solved in RSpec 0.8.2

I loves me some RSpec, but I’ve had this consistent problem on my last two projects when RSpec and Rcov are run together: Sometimes you get Seg Faults. In a previous post I talked about my solution to this (redefining the new method on ActiveRecord objects), but it was a hacky solution and I’m glad to say that it’s out of the code base as of today. On a hunch this weekend I installed RSpec 0.8.2 (we had been using 0.7.5.1), took out my super-fun hacktacular solution from a spec and it ran fine. But why? Looking through RSpec’s list of bugs fixed I didn’t see any reference to the bug I logged a few months ago (I didn’t really expect too – they were never able to reproduce it) but I do have any idea. David Chelimsky (lead dev of RSpec) had been telling me for awhile about how he was going to change RSpec to stop using method_missing on object because when Rails takes it for its own purposes, then RSpec has to some hacky things to steal it back (David wrote about it in ...