How to write unit tests with respect to model callbacks?

Hello,

I am exploring the “Testing” part of Rails, but It seems some things
work differently than I thought it would.

Consider the following model:

class Client < ActiveRecord::Base

has_one :project

def after_create
Project.new(:name => self.name, :is_client => true, :client_id
=> self.id).save
end

def after_update
self.project.update_attributes(:name => self.name, :disabled =>
self.disabled)
end

def before_destroy
self.project.destroy
end

end

and the following test:

require File.dirname(FILE) + ‘/…/test_helper’

class ClientTest < Test::Unit::TestCase
fixtures :clients

def setup
@client = Client.find(1)
end

def test_create
assert_kind_of Client, @client
assert_equal 1, @client.id
assert_equal clients(:elasto_client).name, @client.name
end

def test_update
assert_equal clients(:elasto_client).description,
@client.description
@client.description = “TEST UPDATE DESCRIPTION”
assert @client.save, @client.errors.full_messages.join("; ")
@client.reload
assert_equal “TEST UPDATE DESCRIPTION”, @client.description
end

def test_destroy
@client.destroy
assert_raise(ActiveRecord::RecordNotFound) {
Client.find(@client.id) }
end
end

larik@somehost $ ruby test/unit/client_test.rb
Loaded suite test/unit/client_test
Started
.EE
Finished in 0.577375 seconds.

  1. Error:
    test_destroy(ClientTest):
    NoMethodError: You have a nil object when you didn’t expect it!
    You might have expected an instance of ActiveRecord::Base.
    The error occured while evaluating nil.destroy
    /Users/larik/cvs/correlator/app/models/client.rb:46:in
    before_destroy' /usr/lib/ruby/gems/1.8/gems/activerecord-1.13.2/lib/active_record/callbacks.rb:348:insend’
    /usr/lib/ruby/gems/1.8/gems/activerecord-1.13.2/lib/active_record/callbacks.rb:348:in
    callback' /usr/lib/ruby/gems/1.8/gems/activerecord-1.13.2/lib/active_record/callbacks.rb:320:indestroy_without_transactions’
    /usr/lib/ruby/gems/1.8/gems/activerecord-1.13.2/lib/active_record/transactions.rb:122:in
    destroy' /usr/lib/ruby/gems/1.8/gems/activerecord-1.13.2/lib/active_record/transactions.rb:122:intransaction’
    /usr/lib/ruby/gems/1.8/gems/activerecord-1.13.2/lib/active_record/transactions.rb:91:in
    transaction' /usr/lib/ruby/gems/1.8/gems/activerecord-1.13.2/lib/active_record/transactions.rb:118:intransaction’
    /usr/lib/ruby/gems/1.8/gems/activerecord-1.13.2/lib/active_record/transactions.rb:122:in
    destroy' test/unit/client_test.rb:25:intest_destroy’

  2. Error:
    test_update(ClientTest):
    NoMethodError: You have a nil object when you didn’t expect it!
    You might have expected an instance of ActiveRecord::Base.
    The error occured while evaluating nil.update_attributes
    /Users/larik/cvs/correlator/app/models/client.rb:42:in
    after_update' /usr/lib/ruby/gems/1.8/gems/activerecord-1.13.2/lib/active_record/callbacks.rb:348:insend’
    /usr/lib/ruby/gems/1.8/gems/activerecord-1.13.2/lib/active_record/callbacks.rb:348:in
    callback' /usr/lib/ruby/gems/1.8/gems/activerecord-1.13.2/lib/active_record/callbacks.rb:275:inupdate_without_timestamps’
    /usr/lib/ruby/gems/1.8/gems/activerecord-1.13.2/lib/active_record/timestamp.rb:39:in
    update' /usr/lib/ruby/gems/1.8/gems/activerecord-1.13.2/lib/active_record/base.rb:1431:increate_or_update_without_callbacks’
    /usr/lib/ruby/gems/1.8/gems/activerecord-1.13.2/lib/active_record/callbacks.rb:249:in
    create_or_update' /usr/lib/ruby/gems/1.8/gems/activerecord-1.13.2/lib/active_record/base.rb:1226:insave_without_validation’
    /usr/lib/ruby/gems/1.8/gems/activerecord-1.13.2/lib/active_record/validations.rb:698:in
    save_without_transactions' /usr/lib/ruby/gems/1.8/gems/activerecord-1.13.2/lib/active_record/transactions.rb:126:insave’
    /usr/lib/ruby/gems/1.8/gems/activerecord-1.13.2/lib/active_record/transactions.rb:126:in
    transaction' /usr/lib/ruby/gems/1.8/gems/activerecord-1.13.2/lib/active_record/transactions.rb:91:intransaction’
    /usr/lib/ruby/gems/1.8/gems/activerecord-1.13.2/lib/active_record/transactions.rb:118:in
    transaction' /usr/lib/ruby/gems/1.8/gems/activerecord-1.13.2/lib/active_record/transactions.rb:126:insave’
    test/unit/client_test.rb:19:in `test_update’

3 tests, 4 assertions, 0 failures, 2 errors

It seems like the data for the clients is directly loaded from the
fixtures files, it doesn’t respect the callbacks defined in the model.
E.g. creating of the Project data.

My question is, what is the best way of getting “proper” data in the
database, with respect to the fixtures data and the callbacks defined
in the model.


Sincerely,

Frodo L.

Hi !

2005/12/22, Frodo L. [email protected]:

It seems like the data for the clients is directly loaded from the
fixtures files, it doesn’t respect the callbacks defined in the model.
E.g. creating of the Project data.

My question is, what is the best way of getting “proper” data in the
database, with respect to the fixtures data and the callbacks defined
in the model.

Yes, fixtures data is copied from the fixtures file to the DB, sans
transformation. If you want the callbacks to execute, you’ll have to
create the data yourself, using ActiveRecord instances.

On the other hand, fixtures are made to be loaded quickly and
efficiently in the DB. So, just add a project to the projects.yml
file, and in the fixtures line of the test case, refer to the projects
fixture as well as the clients fixture.

Hope that helps !