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_test

Foreword

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
  end

Alpha 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
  end

And 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
  end

That 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.

Posted in  | 5 comments | no trackbacks

Comments

  1. James said about 14 hours later:

    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.

  2. Mathew Abonyi said about 14 hours later:

    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?

  3. Mathew Abonyi said 1 day later:

    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.

  4. Benjamin said 1 day later:

    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/

  5. Mike said 14 days later:

    Looking forward to a more complete release :) Don’t have time to sift through it at this point, but I am definitly interested!

Trackbacks

Use the following link to trackback from your own site:
http://www.mathewabonyi.com/articles/trackback/22

Comments are disabled