Pivotal Labs

Main menu

Skip to primary content
Skip to secondary content
  • About
  • Case Studies
  • Team
    • Executives
    • Locations
      • San Francisco (HQ)
      • Boston
      • Boulder
      • Denver
      • London
      • Los Angeles
      • New York
  • Community
    • Blogs
    • Tech Talks
    • Events
  • Careers
    • Lifestyle
    • Principles & Practices
    • Benefits
    • FAQ
    • Apply
  • Contact
    • Press Room
    • Press Releases
    • In The News
    • Press Kit
  • All
  • Labs
  • Standup
  • Tracker
Cameron Cundiff

[Standup][NY] 07/30/12 and 07/31/12

Cameron Cundiff
Tuesday, July 31, 2012

Interestings

  • Frank – Cucumber like framework for iOS – trending on HackerNews.
  • rspec shared_example names do not get scoped within describe blocks

    As of rspec 2.6, shared examples are global. You can declare them in a describe block, but they are not scoped to that description. This ultimately means that shared_example names should be unique across your test suite!

  • 0 Shares
  • Share on Facebook
  • Share on Twitter
Mark Rushakoff

RSpec: Asserting arrays’ content without regard to order

Mark Rushakoff
Monday, May 21, 2012

Sometimes I want to make assertions about the content of an array when the order of its content is not guaranteed:

nums = [1,2,3].shuffle
nums.length.should == 3
nums.should include 1
nums.should include 2
nums.should include 3

(Of course this is a contrived example, and we could just write nums.sort.should == [1,2,3]. But sometimes we are working with objects that aren’t already sortable.)

I recently found out that RSpec has an array matcher that is specifically intended for this use case, via the =~ operator:

[1,2,3].shuffle.should =~ [1,2,3]
  • 0 Shares
  • Share on Facebook
  • Share on Twitter
Stephan Hagemann

Never use shared examples groups! Usually.

Stephan Hagemann
Friday, March 9, 2012

Shared example groups are a feature of rspec that allow specifying common behavior in a reusable group of specs.

I believe that there is a very specific way in which one can benefit from shared examples groups (and should keep them) and many more in which they come in handy at some point and should be refactored away from as development continues.

When shared examples may seem a good idea

If an application employs mechanisms such as mixins, delegation, or inheritance (which every Rails app by default does…), one can probably find some common behavior. Take a soft-delete functionality for example: specifying for each class that it’s objects are soft-deletable and that it_behaves_like :soft_deletable seems nice, but comes at a cost (and isn’t appropriate).

Shared examples make for a slow test suite

If there are n test cases and m specs in the shared examples, there is a total of n*m specs that will run. Obviously the shared example saves a lot of spec coding: m shared specs, and n references to it. Meaning you need to write only n+m specs.

If, however, it were possible to test the common functionality separately (m specs) and then test only its integration (n specs), there would still be n+m specs to write, but more importantly, there would also be only n+m specs to execute.

n*m vs. n+m, that’s a huge difference.

How to test common code without shared example groups

There are a couple of ways to test common code without resorting to shared examples.

In your spec, write a test harness class that gets your mixin, delegate, or (abstract) super class. This class only has the abilities of a non-special object and the common code. Testing this class allows testing the common code in an isolated way.

If you happen to be relying on ActiveRecord for your mixin as soft-deletable probably would be, use Temping to create an ActiveRecord object that only has ActiveRecord::Base behavior and that of the common code.

In case you have shared example groups in place, but can’t apply either of the above options, you probably haven’t extracted the code enough yet. Do that first and then come back here and refactor away from the shared example group.

Is a shared example group ever the right thing to do?

Imagine a mixin that has complex interactions with the objects it gets mixed in to, like a it_behaves_like :fuzzy_matchable. Fuzzy matching will always work in a similar way, but be working on different attributes or methods depending on the object. In this case the interactions between the object and the mixin are important to specify and verify. David Chelimsky describes this situation in his post about specifying Mixins with shared example groups. This kind of complex interaction seems to me to be the only case in which shared example groups are truly beneficial.

Am I missing good use cases of shared example groups here? Where do you use them?

  • 0 Shares
  • Share on Facebook
  • Share on Twitter
Stephan Hagemann

Specific interfaces – in the small

Stephan Hagemann
Wednesday, March 7, 2012

Everyone on the Web I found who states that quote I was looking for says “I don’t know who said it, but be ‘Generous on input, strict on output’” (or some variation on this). While I am unsure about the first proposition, I wholeheartedly agree with the second.

Edit 3/8: the quote is known in a different wording as Postel’s Law, which shows up as the Robustness Principle in RFC 793, the specification of TCP. Thanks for the hint, Austin!

Unfortunately, the closest a Rubyist typically gets to the implementation of an interface specification is his tests. This provides a pretty good, but somewhat disconnected specification that can sometimes cover up imprecisions in the interface’s implementation.

On top of that, sometimes our frameworks make it easy to forget what our tests are asserting or spec’ing.

Take rspec’s predicate matchers and this example:

require 'rspec/core'

class VeryImportantQuestions
  def self.really?(answer)
    answer == 'Yes. I am telling you.'
  end

  def self.really_really?(answer)
    answer == 'Yes. I am telling you.' ? 42 : nil
  end
end

describe "really?" do
  context "using rspec predicate matchers" do
    context "if someone is telling you" do
      it "should be really really the case and return true" do
        VeryImportantQuestions.really?('Yes. I am telling you.').should be_true
      end
    end
    context "if someone is not sure" do
      it "should return false" do
        VeryImportantQuestions.really?('I am not sure.').should be_false
      end
    end
  end
end

describe "really_really?" do
  context "using rspec predicate matchers" do
    context "if someone is telling you" do
      it "should be really really the case and return true" do
        VeryImportantQuestions.really_really?('Yes. I am telling you.').should be_true
      end
    end
    context "if someone is not sure" do
      it "should return false" do
        VeryImportantQuestions.really_really?('I am not sure.').should be_false
      end
    end
  end
end

be_true and be_false effectively hide the fact that what’s actually spec’ed is truthiness and falsiness. Only when the following context is added is this imprecision revealed:

  context "spec'ing the actual output of the method fails" do
    context "if someone is telling you" do
      it "should be really really the case and return true" do
        VeryImportantQuestions.really_really?('Yes. I am telling you.').should == true
      end
    end
    context "if someone is not sure" do
      it "should return false" do
        VeryImportantQuestions.really_really?('I am not sure.').should == false
      end
    end
  end

With regard to rspec, I suggest to consider twice whether the benefits of using specific matchers to not outweigh their benefits in your situation. You might get nicer test output, but you might lose the ability to immediately tell what you’re spec’ing.

With regard to tests in general: be specific about what you output – aka be specific about what you test.

Here is the gist: https://gist.github.com/1998462

  • 0 Shares
  • Share on Facebook
  • Share on Twitter
Stephan Hagemann

Boulder Standup – Feb 16, 2012

Stephan Hagemann
Thursday, February 16, 2012

rspec should render_template still behaving weirdly

Specing a partial being rendered with render_template blows up. What to do?

render_template has been brittle for a long time. It obviously still is:

response.should render_template("template") #works fine
response.should render_template(partial: "template") #works fine
response.should render_template(partial: "template", locals: {local_array: []}) #blows up within rspec

You know how to fix it? Solve it here

RubyMine 4 is out

RubyMine “compare two files” isn’t broken

It is just really, really weird: if you have to scroll when comparing two files check the file that is above in the project drawer first. If you scroll up to do select the second file to compare, the compare window won’t open.

Stubbing can? can be hard

In a system with a lot of cancan abilities – what is the best way to stub a particular ability for controller specs? In the hierarchy of controllers, a lot of abilities may be checked, all of which would need to stubbed in order to get to the code under test.

Instead of stubbing the abilities, create a new, anonymous, ability class specific for your spec that gets all the necessary abilities and then stub current_ability to return an instance of that class. Internally cancan calls current_ability when you call can?: cancan controller additions

  • 0 Shares
  • Share on Facebook
  • Share on Twitter
Grant Hutchins

Standup 01/09/2012: Lightning and Rakes

Grant Hutchins
Tuesday, January 10, 2012

Help

“RSpec 2.8 is out. The Rake runner in TeamCity isn’t yet working.”

The suggestion was to update to an EAP release of TeamCity.

Events

  • Tuesday, January 10, 2012: NYC.rb lightning talks, pizza, and beer after work at Pivotal NYC.
  • 0 Shares
  • Share on Facebook
  • Share on Twitter
Stephan Hagemann

Standup 11/11/2011: Some funkinesses

Stephan Hagemann
Friday, November 11, 2011

Interesting

  • rspec stub != stub!. stub! is an alias method for stub. There is however also a method stub that is an alias for double. If you try to stub a method on the test class (to stub it on the context), you should probably use the magic subject/helper/controller methods. If you don’t, using self.stub(:name => 'result') will create a double, while self.stub!(:name => 'result') will stub the method as you would expect.

  • Asynchronous file creation and downloading: if an asynchronous process writes a file using File.open and f.write, an other process checking the presence of the file to determine whether it is already available for download, will deliver the empty file, if the file has been opened, but not yet written.

    • Workarounds:
      • if you have one write to the file only: check filesize.
      • update an ActiveRecord attribute after the file writing is completed and check against that.
  • == on DelegateClass: newing up an instance delegate_x of DelegateClass from object x, x == delegate_x, while of course x.class != delegate_x.class.

Keystroke of the day

  • Rubymine KOTD: The search+replace mode you reach via Cmd+r allows you to see recent searches by hitting the down arrow. If that doesn’t work for you in Lion, hit Ctrl+h.
  • 0 Shares
  • Share on Facebook
  • Share on Twitter
Georg Apitz

Fixture builder and rspec-acceptance

Georg Apitz
Monday, September 26, 2011

Getting rspec-acceptance (webdriver, no cucumber) to work correctly with fixture_builder and database_cleaner can be a bit of a drag.

It is actually not that hard and there are resources all over the inter tubes, you just have to find them.
For the sake of saving myself and some fellow programmers some time I will summarize the process we followed.

First, you need to make sure to have the fixture_builder, database_cleaner and while we’re at it headless gems installed.
Then the bulk of the work happens in acceptance_helper.rb, spec_helper.rb and fixture_builder.rb.

Details on what is in them are below. There are some notable things which I mention in context with the code.

spec_helper.rb

If you need you fixtures loaded in a particular order
you can load them in that order by specifying them as argument for the config.global_fixtures variable in spec_helper.

ENV["RAILS_ENV"] ||= 'test'
require File.expand_path("../../config/environment", __FILE__)
require 'rspec/rails'

Dir[Rails.root.join("spec/support/**/*.rb")].each {|f| require f}

RSpec.configure do |config|

  config.include ObjectCreationHelper
  config.include ObjectCreationMethods
  config.mock_with :rspec

  config.global_fixtures = :all

  # Remove this line if you're not using ActiveRecord or ActiveRecord fixtures
  config.fixture_path = "#{::Rails.root}/spec/fixtures"

  # If you're not using ActiveRecord, or you'd prefer not to run each of your
  # examples within a transaction, remove the following line or assign false
  # instead of true.
  config.use_transactional_fixtures = true

  config.before(js: nil) do
    config.use_transactional_fixtures = true
  end

end

accptance_helper.rb

Here headless (enables running selenium tests on a ci-server without a browser) and data_base cleaner are set up.
Database_cleaner will clean everything in the specified interval (in my case after each test) unless tables are specified in the “except” option for the database_cleaner strategy.
It is important to turn transactional fixtures off before running specs that require js and turn them back on after they have run
to ensure rspec spec still runs, assuming that there are spec files that have both test that require js and some that don’t require js.

require 'spec_helper'
require 'capybara/rspec'
require 'capybara/rails'
require 'database_cleaner'
require 'headless'

headless = Headless.new
headless.start

at_exit do
  unless ENV['RUNNING_CI']
    headless.destroy
  end
end

def build_fixtures
  Fixtures.reset_cache
  fixtures_folder = File.join(Rails.root.to_s, 'spec', 'fixtures')
  fixtures = Dir[File.join(fixtures_folder, '*.yml')].map { |f| File.basename(f, '.yml') }
  DatabaseCleaner.clean
  Fixtures.create_fixtures(fixtures_folder, fixtures)
end

RSpec.configure do |config|
  config.before(:suite) do
    DatabaseCleaner.strategy = :truncation, {:except => %w[ ]}
    DatabaseCleaner.clean_with(:truncation)
  end

  # before each test that requires js, turn transactional fixtures off
  # build the fixtures and start the db cleaner
  config.before(js: true) do
    config.use_transactional_fixtures = false
    build_fixtures()
    DatabaseCleaner.start
  end

  # after each spec with js, turn transactional fixtures back on
  # rebuild fixtures
  config.after(:each, js: true) do
    config.use_transactional_fixtures = true
    build_fixtures()
  end
end

fixture_builder.rb

Pretty straight forward, some clean up and checking if fixtures need rebuilding. Since database_cleaner will try to clean all exisiting tables
it is important to exclude database views specifically.

FixtureBuilder::Configuration.class_eval do

  def rebuild_fixtures?
    (@file_hashes != read_config) || Dir.glob('spec/fixtures/**/*.yml').empty?
  end

  def files_to_check
    @files_to_check ||= []
  end

  def delete_tables
    ActiveRecord::Base.connection.execute('SET FOREIGN_KEY_CHECKS=0')
    tables.each { |t| ActiveRecord::Base.connection.delete(delete_sql % ActiveRecord::Base.connection.quote_table_name(t)) }
  ensure
    ActiveRecord::Base.connection.execute('SET FOREIGN_KEY_CHECKS=1')
  end

end

FixtureBuilder.configure do |builder|
  builder.files_to_check = Dir["spec/support/fixture_builder.rb"]
  builder.skip_tables += ["current_post_stats_view"]
  builder.factory do

    united_states = Country.create! :name => "United States", :country_code => "US"
    Country.create! :name => "Canada", :country_code => "CA"

    admin_user = User.create! do |user|
      user.first_name = "Admin"
      user.last_name = "User"
      user.email = "admin@super_site_.com"
      user.password = "password"
      user.password_confirmation = "password"
      user.role = "admin"
    end
    name("admin", admin_user)

  end
end
  • 0 Shares
  • Share on Facebook
  • Share on Twitter
Glenn Jahnke

Standup 2011.04.12: Tweeting Standup and RSpec

Glenn Jahnke
Tuesday, April 12, 2011

Interestings

It was suggested that we should Tweet our standups as well as post them to our blog.

Helps

What is the overhead of an RSpec “it” block?

People seem to think the overhead is really negligible compared to Rails load time or making any DB calls whatsoever. People have seen whole codebases moved from TestUnit to RSpec with no notable speed slow-down.

  • 0 Shares
  • Share on Facebook
  • Share on Twitter
Pivotal Labs

RSpec 2 Gotcha with polymorphic_path

Pivotal Labs
Wednesday, December 8, 2010

A quick gotcha we ran into when using polymorphic path and rspec2 today.

In a controller test we had an assertion:

response.should redirect_to(polymorphic_path(@some_object))

Which resulted in the following error

Failure/Error: Unable to find matching line from backtrace stack level too deep
# ~/.rvm/gems/ruby-1.9.2-p0@gemset/gems/rspec-expectations-2.1.0/lib/rspec/matchers/method_missing.rb:4

It turns out polymorphic path is not available in the controller test (but the usual object_path method is). As to why this throws a stack level too deep and not a method undefined looks like potentially another bug in rspec but the solution seemed to be to do the following in our spec_helper.b for Rails 3:

include Rails.application.routes.url_helpers

For Rails 2.x you’ll want to use:

include ActionController::UrlWriter

I’ve opened an issue for this on github as well https://github.com/rspec/rspec-expectations/issues/issue/46

  • 0 Shares
  • Share on Facebook
  • Share on Twitter

Topics

  • agile (778)
  • rails (113)
  • testing (86)
  • ruby (83)
  • ruby on rails (70)
  • jobs (62)
  • javascript (54)
  • techtalk (44)
  • rspec (38)
  • activerecord (29)
  • productivity (29)
  • gogaruco (29)
  • ironblogger (29)
  • git (28)
  • nyc (27)
  • rubymine (25)
  • mobile (22)
  • bloggerdome (20)
  • cucumber (20)
  • process (19)
  • pivotal tracker (19)
  • jasmine (19)
  • design (18)
  • ios (18)
  • webos (17)
  • objective-c (17)
  • android (16)
  • palm (16)
  • "soft" ware (16)
  • fun (15)
  • tracker ecosystem (15)
  • ci (15)
  • cedar (15)
  • rails3 (14)
  • performance (14)
  • bdd (14)
  • gem (13)
  • selenium (12)
  • css (12)
  • goruco (12)
  • bundler (12)
  • tdd (12)
  • meetup (11)
  • railsconf (11)
  • nyc-standup (11)
  • capybara (10)
  • mac (10)
  • mojo (10)
  • chef (10)
  • rubygems (9)
Subscribe to rspec Feed
  1. ←
  2. 1
  3. 2
  4. 3
  5. 4
  6. →
  • About
  • Case Studies
  • Team
  • Community
  • Careers
  • Contact
  • Labs
  • Events

Contact Us

contact@pivotallabs.com
+1 415-77-PIVOT
TwitterLinkedInFacebook

Pivotal Tracker

Tracker is the award-winning agile project management tool that enables real-time collaboration around a shared, prioritized backlog.
Visit pivotaltracker.com >