6

I have a before_validation :do_something, :on => :create in one of my models.

I want to test that this happens, and doesn't happen on :save.

Is there a succinct way to test this (using Rails 3, Mocha and Shoulda), without doing something like:

context 'A new User' do
  # Setup, name test etc
  @user.expects(:do_something)
  @user.valid?
end

context 'An existing User' do
  # Setup, name test etc
  @user.expects(:do_something).never
  @user.valid?
end

Can't find anything in the shoulda API, and this feels rather un-DRY...

Any ideas? Thanks :)

nfm
  • 19,689
  • 15
  • 60
  • 90
  • OK, in case you do find a matcher/write one or someone comes up with one for :before_validation, make sure to use this simple technique from this [post](http://stackoverflow.com/questions/3134066/shoulda-rspec-matchers-on-create/5372151#5372151) to solve the bit to do with :on => create. A pretty simple solution using the "subject" block. – jake Sep 19 '11 at 05:44

2 Answers2

9

I think you need to change your approach. You are testing that Rails is working, not that your code works with these tests. Think about testing your code instead.

For example, if I had this rather inane class:

class User
  beore_validation :do_something, :on => :create

  protected

  def do_something
    self.name = "#{firstname} #{lastname}"
  end
end

I would actually test it like this:

describe User do
  it 'should update name for a new record' do
    @user = User.new(firstname: 'A', lastname: 'B')
    @user.valid?
    @user.name.should == 'A B' # Name has changed.
  end

  it 'should not update name for an old record' do
    @user = User.create(firstname: 'A', lastname: 'B')
    @user.firstname = 'C'
    @user.lastname = 'D'
    @user.valid?
    @user.name.should == 'A B' # Name has not changed.
  end
end
Pan Thomakos
  • 34,082
  • 9
  • 88
  • 85
  • While I completely agree with your above statement, your suggested solution might not be the most terse way. Think of it from the perspective of, I don't want to test the :do_something method itself. (this could well be a public method on the call which is more complex and could just be tested directly) But I want to test where this is indeed hooked up on the before validation callback. I think some of the shoulda matchers take this approach. – jake Sep 19 '11 at 05:14
  • But again if :do_something is a private method meant only for this purpose, I agree testing the overall effect save/or valid? is the right way to go. This will also the tests to not break in case you decide not use the callback approach altogether. Either case , important to not try to test the framework. – jake Sep 19 '11 at 05:16
3

You might like the shoulda callback matchers.

Patrick Reiner
  • 858
  • 8
  • 7