Project Ramon

A learning journey from a Ruby noob perspective

Framework agnostic TDD – Intro to Test::Unit methods

test_unit_vs_rspec_header_img

Whether we’re using Test::Unit or Rspec to test-drive our project, the components of a test are very similar. You can find my first post on this topic here.

I found this excerpt in the book Rails Test Prescriptions by: Noel Rappin:

Inside each test, you are generally trying to do four things:

  • Set up the data needed for the test
  • Perform the action that triggers the behavior being tested
  • Perform one or more assertions to verify that the behavior triggered in the previous step had the expected results
  • Tear down any data structures that need to be removed before the next test runs

There are about twenty methods that assert the presence or absence of a particular state.
The assert method is considered the simplest, and takes a boolean argument. If the argument is true, the assertion passes and vice versa.

Here is an illustration using the assert method:

test_unit_vs_rspec_img1

In the example above, starting at line 3 we have the first two steps mentioned at the beginning of the post handled. I set up the data we needed for our test using FactoryGirl.build :user and used a little shortcut I’ve learned from my AirPair‘s of assigning a default value of "Bill" to the attribute :first_name.

Don’t let the colon : position throw you off, it used to not make sense to me either. The attribute :first_name is of the type symbol, but when we pass an assignment to :first_name we are using the new hash syntax. Unfortunately the Ruby 2.0 docs are still using the old format, but here is a peak anyhow, as it illustrates that we could have passed a default value for :first_name like so:

Next in our illustrations, we execute step three of the four things we need to do in each test.
We use the assert method which if we remember from earlier, returns a boolean result, that the parameters inside of assert contain equal values. In other words we’re checking that user1.first_name contains the string "Bill".

And as for step four, since we did not actually commit this record into a database we have nothing to tear down. We were able to bypass saving to our database by calling the .build method on FactoryGirl. If we did need to have this object committed then we could have changed out .build and used .create instead.

Now that we have a brief example of how to shape up a test, the rest is all easy sledding from hear. Lets go over a few Test::Unit methods and what they do.

Test::Unit methods

Before we start, it should be noted that a lot of these methods contain an optional 3rd argument that lists a failure message. According to the Rails Test Prescriptions book, this should be left off, at least within the context of chapter 2.

assert_equal(expected, actual, failure_msg=nil) tests for the expected value to equal the actual value.

This method is nearly synonymous with assert in regards to both returning a true/false value for equality. The difference is that assert_equal accepts two arguments and checks them for equality, whereas assert just checks one argument for true/false.

assert_not_equal(expected_val, actual_val, failure_msg=nil) tests if expected is not equal to actual.

This is self explanatory and is the antithesis of the assert_equal method.

assert_not_nil(expression, failure_msg=nil) tests if the expression is not nil.

assert_respond_to(object, method, failure_msg=nil) tests if the given object will respond to the given method.

Summation

Ok so we’ve covered a few Test::Unit methods, following the four-step template earlier in the post, we can use these methods to test our projects in Ruby or Rails just as we would use Rspec. In my next post I will revisit some Rspec methods that we’ve covered in other posts, and also cover some additional options that Rspec provides in the syntax department.

If you’d like to learn more about TDD, why not check out this Rocky Mountain Ruby talk by Mike Nicholaides.

Advertisements

Categories: AirPair, Newbie, Ruby

Tags: , , ,

6 replies

  1. assert_equal(user1.first_name == “Bill”)

    should really be:
    assert_equal( ‘Bill’, user1.first_name)

    That’s the whole point of the _equal: instead of providing a single bool condition, we specify what is expected vs. what we get. That’s why the framework can then say ‘ooops – expected Bill but got John’, because it can compare the values.

  2. Also noob here. I’m thinking that you are not really testing a requires here, but more of an “accepts.” You’re providing the user’s first_name, right, so it (validates) will not throw an exception on missing first_name. In what ways might you prove that it will require first_name? (Not by providing it, but by NOT providing it, and expecting the exception.

    Am I on the right track here? Just trying to get my teeth into TDD & Rails.

    • Hello Bob,

      I think the point out you made is correct.

      If I wanted to use the word requires instead of accepts in my spec, I should have included something like: it { should validate_pressence_of(:first_name) }, if I was using Test::Unit’s shoulda matchers.

      This way if the attribute value was left blank in my tests, or I forgot to add this validation to my model it would fail from my understanding.

      Here is a link to Thoughtbot’s shoulda matchers github:

      https://github.com/thoughtbot/shoulda-matchers

      I also agree that it would have been beneficial to add a failing case where, as you mentioned, we expect failure when the validation of presence wasn’t met.

      Thank you for commenting on this!

      Ramon

Trackbacks

  1. AirPair.com – What I’ve Learned pt. 2 | Project Ramon
  2. Learn Ruby Test Driven Development with a Ruby Mentor

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s