Unit Testing a Book Inventory Management System
(Page 1 of 2 )
In this seventh part of an article series on the scaffolding feature of Ruby on Rails, we'll continue testing our example book inventory management system. In this part, we'll focus on one-to-many and many-to-many mapping. This article is excerpted from chapter three of the book Practical Rails Projects, written by Eldon Alameda (Apress; ISBN: 1590597818).
Unit Testing the ActiveRecord Mappings
You want to be sure that the mapping between authors, books, and publishers works. George won’t be happy at all, if there’s a bug in the code that prevents him from adding the latest best-sellers to the catalog.
Adding Fixtures for Books and Publishers
We’ll verify that the mapping works by creating unit tests for the mapping code. But let’s first add some useful data to thebooksandpublishersfixture files, which we’ll use in later tests.
Opentest/fixtures/books.ymland add the following two books:
Note that thepublisher_idcolumn has been added to the fixture. This is a reference to a row in the database, which is inserted by thepublishers.ymlfixture file. Currently, no publisher has anidequal to 1, so you’ll need to add the data to thepublishersfixture file to complete the mapping.
Tip You can write ERB in fixtures in the same way as in views. This allows you to create dynamic fixtures, as demonstrated in thebooks.ymlfixture file, whereTime.nowis used to generate thepublished_atvalue. Although dynamic fixtures are useful in some situations, they should generally be avoided as they make tests more complex and less predictable.
Next, add a publisher to thetest/fixtures/ publishers.ymlfile:
Recall that you specify the fixtures that the unit test should load by adding afixturesdeclaration. A couple of tests that we will implement later in this chapter depend on theauthors,publishers, andbooksfixtures. Thebooksfixture has not been added to the test yet, so change thefixturesline in the unit test as follows:
fixtures :authors, :publishers, :books
Unit Testing the One-to-Many Mapping
Now we’ll put the data into use and verify that we can access a collection of books from a publisher. This is done by adding the new test,test_has_many_and_belongs_to_mapping, to thetest/unit/book_test.rbunit test:
book = Book.new(
apress.books << book
assert_equal 3, apress.books.size
Note The unit test doesn’t callbook.saveexplicitly. ActiveRecord is smart enough to know that it must persist the book to the database when the book is added to the author’s collection of books. Also note that you could useassert_difference(introduced in the previous chapter), instead of two calls toassert_equal.
The unit test performs the following tasks in order:
Note The order the fixtures are listed in is important. The fixture data is inserted in the order it is listed. For example, putting thepublishersfixture after thebooksfixture would result in a foreign key error when the test is run and Rails tries to insert the fixture data:ActiveRecord::StatementInvalid: Mysql::Error: Cannot add or update a child row: a foreign key constraint fails.
Next, run the unit tests. You should see all tests pass without any errors.
$ ruby test/unit/book_test.rb
3 tests, 13 assertions, 0 failures, 0 errors --------------------------------------------
To see the SQL that is executed by ActiveRecord behind the scenes, tail thelogs/test.logfile by executing the following command in a separate console window:
$ tail -f logs/test.log
This will monitor the log for changes and print them out to the screen.
Run the unit tests again. You should see the following output from thetest_has_many_ and_belongs_to_mappingtest that you just implemented:
--------------------------------------------SQL (0.000000) BEGIN
As you can see from the first and last line in the sample output, each test is wrapped in a transaction, and changes done by the test are rolled back at the end of the test.blog comments powered by Disqus