Introduction to Unit Testing with Ruby

Overview

Automated unit testing is a ubiquitous practice whereby software engineers can test their code as they are writing it. Unit testing leads to simplified designs, robust code, and increased evidence that your code does what you think it does.

A good unit test is:

Ruby Unit Testing

Today, we’ll be writing our unit tests with Ruby’s Test::Unit::TestCase. This is a built-in library that lets us organize our tests. We need to write a method that implements the math function factorial.

  1. Start your activity journal.
  2. Download factorial.rb and factorial_test.rb.

  3. Take a look, but DO NOT start writing code in factorial.rb YET (that comes a few steps later). We’ll use our tests to drive what code we write in factorial.

  4. Open up and read through the given factorial_test.rb in your text editor. This is a basic skeleton of a Ruby unit test. At the top are the require calls that bring in the code we need. We’ll need to access our own code in factorial.rb, so we require the file, which is in the same directory (hence the relative_require). We also need the Ruby unit testing library. Note that we don't use the .rb extension when we use require methods.

    Furthermore, in Ruby unit testing we need to prefix our method names with test_. Within our test_normal test case we are checking that the factorial(4) is equal to 24. Note that first we specify our expected values, then we specify our actual. The final argument in our assert_equal method is our fail message (what message we should print out if this test fails).

  5. Run the test. Your command and output should look something like this.
    $ ruby factorial_test.rb
    Run options:
    
    # Running tests:
    
    F
    
    Finished tests in 0.000635s, 1575.9671 tests/s, 1575.9671 assertions/s.
    
    1) Failure:
    test_normal(FactorialTest) [factorial_test.rb:8]:
    4! should be 24.
    <24> expected but was
    <nil>.
    
    1 tests, 1 assertions, 1 failures, 0 errors, 0 skips
  6. Before fixing our tests, let's add a second test case. Add a new method called test_another_normal and test that factorial(5) is 120.
  7. Run the test again. This time we should have two failures.
  8. Ok NOW edit factorial.rb Go back and write a simple factorial method. Don't worry about handling all the different cases with negative numbers and such - that will come later. Just think about your test cases. When they pass, it should look something like this:
    Run options:
    
    # Running tests:
    
    ..
    
    Finished tests in 0.000500s, 3999.6720 tests/s, 3999.6720 assertions/s.
    
    2 tests, 2 assertions, 0 failures, 0 errors, 0 skips
  9. Now that you have the base functionality working, it's a good time to submit via Git before we break our code again.
  10. Next, add a new test called test_zero that checks that factorial(0) is 1
  11. Write the code to get all of your tests to pass. (Hint: try to do this part without if-statements)
  12. Commit and submit!
  13. Next, add a new test called test_negative that will test expecting an exception. Look up the Ruby documentation for assert_raise and the documentation for raise.
  14. Write the code in factorial to get all of your tests to pass.
  15. Commit and submit!
  16. Finally, add a new test called test_string that will test that factorial rejects a string. This is another one for assert_raise.
  17. Write the code in factorial to get all of your tests to pass.
  18. Commit and submit!
  19. Clean up your code. Make it readable. Reduce the visual complexity by simplifying variable initialization, reducing if-statements, etc. Keep those unit tests passing throughout this step.
  20. Commit and submit!

Submission

Submit via Git to the Factorial folder. Don't forget your activity journal.