ActiveTest: Rails-style testing
Posted by Mathew Abonyi Tue, 15 Aug 2006 04:49:00 GMT
In pursuit of my previous post, I’ve followed up with an alpha mock-up of my ideas on how Rails testing can be made less tedious. Here’s the first version readme:
Cautionary Word
USE AT YOUR OWN PERIL. ACTIVETEST IS NOT FINISHED. IT HAS BUGS. IT IS MISSING A LOT OF FEATURES.
Balls to Caution. How do I install?
$ ./script/plugin source http://mabs29.googlecode.com/svn/trunk/plugins
$ ./script/plugin install active_testForeword
You will see a lot of similarities between ActiveTest and its paronymic relative, ActiveRecord. I think it best to explain here. Other implementations which are attempting, with various success, to extend the functionality of Test::Unit and make it more Rails friendly have their own unique ways of setting up and developing. The price of their uniqueness is that they move away from the traditional thinking of a Rails developer. They introduce more complications of design and elements to be aware of, meaning more time to understand how something can be done. I do not want to think about the nuances of a test suite and model. The closer they are to each other in design and usage, the easier it is to test them rapidly.
So, without being overly creative, but instead using the conventions of Rails development in the development of Rails itself, I think, basically, ripping off ActiveRecord’s design (which is a perfectly good one for this purpose) is not such a bad idea. It eases the pain of learning how to use ActiveTest and it brings the mentality of Rails closer to tests. This is the whole point of ActiveTest: Rails-like testing.
Description
ActiveTest is an attempt – yet another – at making Test::Unit fit into the mould of Rails, a la ActiveRecord and ActionController. It uses a Base class from which are extended a number of Subjects, each subject including a specific set of Asserts. Each Asserts module can extend the instance methods of a test suite, such as ‘assert_is_a_hippo’, as well as the class methods. It is the class method idea which allows you to create ActiveRecord/ActionController style macros.
Read on for more specifics.
Subjects
Subjects are the types of tests you will run, like Controller, Model, Helper, View, Stress and Integration. Virgin Subjects can be created by extending the ActiveTest::Subject class itself, exactly how one creates new models inheriting from ActiveRecord::Base. You can, if you wish to have a completely blank slate, inherit directly from ActiveTest::Base too.
The best way to think of subjects is that they are pre-made ActiveRecord models. Everyone has a controller, view, helper, or record, so we can make certain assumptions which ActiveRecord cannot. We are not differing from the ActiveRecord metaphors. We are just filling in some blanks for convenience. If you don’t like the convenience, just extend ActiveTest::Base. You’ll get all the fancy stuff of Test::Unit::TestCase, no less and certainly no more.
You can create custom subjects like so:
class ActiveTest::FlyingRhino < ActiveTest::Subject
endAlpha Note: At present, there is no advantage to doing this.
Assertions
ActiveTest allows you to create ‘assertion packages’. Think ‘Acts As …’. If you want a new assertion suite for a particular Subject, all you need to do is create a plugin with this init.rb:
ActiveTest::PickASubject.class_eval do
include ActiveTest::Asserts::YourAssertions
endAnd in your plugin/lib:
module ActiveTest
module Asserts
module YourAssertion
def self.included(base)
base.extend(ClassMethods)
end
module ClassMethods
end
def instance_method
end
end
end
endThat all looks very familiar, doesn’t it?
Examples
Currently, there’s just a Controller subject. An active test would (will) look like this:
class SessionControllerTest < ActiveTest::Controller
setup_controller :login_as => :quentin
test_require_login_for :new, :create, :edit, :update
test_require_permission_for :destroy, :method => :delete
test_index_should_index_items
test_show_should_show_item :id => 1
test_edit_should_edit_item :id => 1
test_update_should_update_item :id => 1
test_destroy_should_destroy_item :id => 1
test_new_should_new_item
test_create_should_create_item
def test_special_case_for_this_controller
end
protected
# overwrite the default create_item, which expects parameters from dynamic class methods
def create_item(action = nil, parameters = {})
super(:create, :session => { :login => 'anotherguy' })
end
end
The class methods create a bunch of tests for you which do precisely what it says: requires login. By default, the Controller subject has the Authentication and Authorisation modules, which assume you are using some variant of Acts As Authenticated.

I look forward to seeing the seeing the full suite!
However, I don’t think you should include anything login-related, for the same reasons Rails doesn’t include anything login-related. People could always add their own require_login_for assertions through a plugin.
I’m beginning to think, yes, the login side should be part of plugins which provide authentication/authorisation. So, for example, my Simple Access Control would have Asserts::Authorisation and automatically stuff it into ActiveTest::Controller if it sees ActiveTest.
What do you think to the design I chose?
svn co http://mabs29.googlecode.com/svn/trunk/plugins/active_test/rdoc
Added RDoc documentation for all the stuff I’m thinking, designing, etc. It’s worth a look to see what is in and what will be coming, especially if you want to influence the direction of ActiveTest.
You’ll definetely want to seperate the login related info from there. If it’s not absolutely dependent, get it out for security reasons mainly. Your logical series of triggers makes sense for “if these see that and so on for design aspects from what I can tell.” - ben @ http://rubyonrailsblog.com/
Looking forward to a more complete release :) Don’t have time to sift through it at this point, but I am definitly interested!