Credit: Pat Eyler
You want to make it easy to run your projects unit test suite. You also want the tests to run automatically before you do a new release of your project.
Require the rake/testtask library and create a new Rake::TestTask. Save the following code in a file called Rakefile in the projects top-level directory (or add it to your existing Rakefile).
require rake/testtask Rake::TestTask.new( est) do |t| t.pattern = est/**/tc_*.rb t.warning = true end
This Rakefile makes two assumptions:
The Test::Unit test cases live in files under the test directory (and its subdirectories). The names of these files start with tc_ and end in .rb.
The Ruby libraries to be tested live under the lib directory. Rake automatically appends this directoy to Rubys load path, the list of directories that Ruby searches when you try to require a library.
To execute your test cases, run the command rake test in the projects top-level directory. The tests are loaded by a new Ruby interpreter with warnings enabled. The output is the same as youd see from Test::Units console runner.
If its easy to trigger the test process, youll run your tests more often, and youll detect problems sooner. Rake makes it really convenient to run your tests.
We can make the test command even shorter by defining a default task. Just add the following line to the Rakefile. The position within the file doesn matter, but to keep things clear, you should put it before other task definitions:
task "default" => ["test"]
Now, whenever we run rake without an argument, it will invoke the test task. If your Rakefile already has a default task, you should be able to just add the test task to its list of prerequisites. Similarly, if you have a task that packages a new release of your software (like the one defined in Recipe 19.4), you can make the test task a prerequisite. If your tests fail, your package won be built and you won release a buggy piece of software.
The Rake::TestTask has a special attribute, libs; the entries in this array are added to Rubys load path. As mentioned above, the default value is ["lib"], making it possible for your tests to require files in your projects lib/ subdirectory. Sometimes this default is not enough. Your Ruby code might not be in the lib/ subdirectory. Or worse, your test code might change the current working directory. Since lib/ is a relative path, the default value of libs would start out as a valid source for library files, and then stop being valid when the test code changed the working directory.
We can solve this problem by specifying the absolute path to the projects lib directory in the Rakefile. Using an absolute path is generally more stable. In this sample Rakefile, we give the load path the absolute path to the lib and test subdirectories. Adding the test directory to the load path is useful if you need to require a library full of test utility methods:
require rake/testtask lib_dir = File.expand_path(lib) test_dir = File.expand_path( est) Rake::TestTask.new("test") do |t| t.libs = [lib_dir, test_dir] t.pattern = "test/**/tc_*.rb" t.warning = true end
As a project grows, it takes longer and longer to run all the test cases. This is bad for the habit we e trying to inculcate, where you run the tests whenever you make a change. To solve this problem, group the test cases into test suites. Depending on the project, you might have a test suite of all test cases concerning file I/O, another suite for the console interface, and so on.
Lets say that when you e working on the DataFile class, you can get away with only running the file I/O test suite. But before releasing a new version of the software, you need to run all the test cases.
To create a Rake test suite, instantiate a Rake::TestTask instance, and set the test_files attribute to something other than the complete list of test files. This sample Rakefile splits up the test files into two suites.
require rake/testtask Rake::TestTask.new( est-file) do |t| t.test_files = [ est/tc_datafile.rb, est/tc_datafilewriter.rb, est/tc_datafilereader.rb] t.warning = true end Rake::TestTask.new( est-console) do |t| t.test_files = [ est/tc_console.rb, est/tc_prettyprinter.rb] t.warning = true end
Invoking rake test-file runs the tests related to file I/O, and invoking rake test-console tests the console interface. The only thing missing is a task that runs all tests. You can either use the all-inclusive task from the Rakefile given in the Solution, or you can create a task that has all the test suites as prerequisites:
task est => [ est-file, est-console]
When this test task is invoked, Rake runs the test-file suite and then the test-console suite. Each suite is run in its own Ruby interpreter.
Date and Time
Files and Directories
Code Blocks and Iteration
Objects and Classes8
Modules and Namespaces
Reflection and Metaprogramming
XML and HTML
Graphics and Other File Formats
Databases and Persistence
Web Development Ruby on Rails
Web Services and Distributed Programming
Testing, Debugging, Optimizing, and Documenting
Packaging and Distributing Software
Automating Tasks with Rake
Multitasking and Multithreading
Extending Ruby with Other Languages