#12 Refactoring User Name Part 3
The last two episodes have concentrated on refactoring and testing. By the end of the last episode we’d refactored our model, but the tests for it were in a bit of a mess. Let’s see what we can do to tidy them up.
require 'test_helper' class UserTest < ActiveSupport::TestCase test "full name without middle initial" do user = User.new(:first_name => "John", :last_name => "Smith") assert_equal 'John Smith', user.full_name end test "full name with middle initial" do user = User.new(:first_name => "Paul", :middle_initial => "P", :last_name => "Hughes") assert_equal 'Paul P. Hughes', user.full_name end test "full name with empty middle initial" do user = User.new(:first_name => "John", :middle_initial => "", :last_name => "Jones") assert_equal 'John Jones', user.full_name end end
The tests for the User
class.
We have three tests and there is a lot of duplication across them. For each test we create a new User
and compare it to a string value. To remove the duplication we’ll create a method that creates a new User
and returns its full_name
.
def full_name(first, middle, last) User.new(:first_name => first, :middle_initial => middle, :last_name => last).full_name end
The new non-test method for the UserTest
class.
Now, each of our tests can be simplified so that they look like this:
test "full name without middle initial" do assert_equal "John Smith", full_name('John', nil, 'Smith') end test "full name with middle initial" do assert_equal 'Paul P. Hughes', full_name('Paul', 'P', 'Hughes') end test "full name with empty middle initial" do assert_equal "John Jones", full_name('John', '', 'Jones') end
The simplified test for a User
with a middle initial.
Of course, the proof that our refactoring has worked is that the tests still all pass.
Laa-Laa:ep11 eifion$ autotest loading autotest/rails /opt/local/bin/ruby -I.:lib:test -rtest/unit -e "%w[test/unit/user_test.rb test/functional/users_controller_test.rb].each { |f| require f }" | unit_diff -u Loaded suite -e Started ... Finished in 0.282538 seconds. 3 tests, 3 assertions, 0 failures, 0 errors
The refactored unit tests still pass.
Now that our tests are straightforward they can be moved in to a single test with three assertions. The only problem with doing that is that if one of the assertions in a test fails it is difficult to know which one it was. We can add a message to each assertion so that it identifies itself if it fails. Our final test class looks like this:
require 'test_helper' class UserTest < ActiveSupport::TestCase test "full name" do assert_equal "John Smith", full_name('John', nil, 'Smith'), 'nil middle initial' assert_equal 'Paul P. Hughes', full_name('Paul', 'P', 'Hughes'), 'P middle initial' assert_equal "John Jones", full_name('John', '', 'Jones'), 'blank middle initial' end def full_name(first, middle, last) User.new(:first_name => first, :middle_initial => middle, :last_name => last).full_name end end
The final refactored UserTest
class.
Over the last three episodes we’ve created unit tests and refactored them along with the code they test to leave both in a much more readable and managable state. While this is a relatively simple example it should persuade you of the benefits of testing and refactoring your Ruby and Rails code.