You know how tests are fundamental for a well-developed project, for this reason we should create step-by-step a net of test cases. Of course we also should be able to change rapidly our tests as the same we do with our code. Ruby on Rails is a great framework, because its shortcuts, the wide usage of DSL etc.. All this stuff can save a lot of time, but what about tests? Are we really able to follow our code?

Create and Destroy

ActiveSupport provides few useful tools to improve our test, I really appreciate assert_difference and assert_no_difference.

Basically, this two methods accepts as arguments a code chunk (as string) and a block. When the test run, it binds the block first, then it assert if the changements caused by the block call are the same expected by first argument.

def test_should_be_created assert_difference 'Person.count' do create_person end end

We are testing a Person creation, we pass as first argument 'Person.count', and the code that should correctly save the person. If the model will be saved, a new record should exists into the database table. At this moment assert_difference evaluates the first argument, and assert if there are differences in the Person count.

def test_should_be_destroyed assert_difference 'Person.count', -1 do destroy_person end end

This example is just a bit different, we are also passing a Fixnum as argument. This because we want assert another difference from the default one, which is +1. So, if the model will be correctly saved, we will have a negative difference, of one, into the Person count.

def test_should_require_first_name_on_create assert_no_difference 'Person.count' do create_person assert person.errors.on(:first_name) end end

The third example uses assert_no_difference, to test aganist model validations. ActiveRecord, by default, prevents the creation of a model if a validation doesn’t pass. In this case our model requires first_name as mandatory attribute, but unfortunately it’s nil, so the creation fails and the brand new record will be not created.

Update

As you can see, those two methods are very useful for test creation and destruction of models, but totally missing the goal of the update. In fact, the update process of a record, doesn’t produces numerical differences.

I created two methods to supply this lack.

def assert_updated(model, message = nil, &block) yield assert_not_equal model.attributes, model.reload.attributes, message end
def assert_not_updated(model, message = nil, &block) yield assert_equal model.attributes, model.reload.attributes, message end

Just add them to your test/test_helper.rb, and they will be available in all your test cases.

def test_should_update assert_updated person do update_person end end

First, you should notice that the first argument it isn’t a string but an ActiveRecord. The behaviour of this method is similar to the previous I illustrated, it first bind the block, then assert if the attributes of the model are different. It internally uses ActiveRecord::Base#attributes which returns an hash of model attributes, then assert the differences with Ruby’s assert_not_equal.

def test_should_require_first_name_on_update assert_not_updated person do update_person assert person.errors.on(:first_name) end end

Similarly to all other examples, it first performs the block, call then assert there are no changes in the model attributes.

Conclusion

Those methods should provide a rapid way to write and mantain your test cases.

If you enjoyed this post, feel free to recommend me on Working With Rails.