imedo Development Blog

there is no charge for awesomeness

Archive for the ‘Testing’ tag

Testing PDF generation

without comments

Generating PDFs in a Rails application is a fairly common task. Maybe you want to create a letter, report, document or maybe an invoice. Either way the stuff that normally ends up in an PDF is important and you want to make sure the right stuff ends up there.

This pretty much sounds like a case for automated testing. But how do you test PDF content? One option would be to generate the PDF and then create a HTML out of the PDF using pdftohtml, parse the HTML and make some assertions. As you can guess, this approach isn’t very feasable, because the generated HTML isn’t very easy to parse.

Most of the time PDF generation in Rails applications is done using the RTex Plugin – the PDF is generated via LaTeX. This makes testing a lot easier because you can just parse and check the generated LaTeX-Source.

Everyone how has seen a LaTeX source file may ask: How the hell do I parse that?

In our case we added some “helper” comments like ”% SUM BEGIN” and ”% SUM END” before and after the part we were interested in and then used basic RegEx to parse out the interesting part. You have to manually check that the markup still looks as expected due to the newline handling of LaTeX (one is ok, two = new paragraph). Most of the time it is sufficient to look for ERB-Tags and use < %- instead of < %.

This approach works pretty well for us. One question which you should always keep in mind when you write tests is: What do I test on this level of testing and what do I leave out.

For the PDF/LaTeX-Testcase we choose to test the basic interaction between the objects that provide values for the PDF generation and the Template. We don’t test all combinations, just a few basic cases. Testing all or at least a lot of combinations, edge cases etc. is clearly a concern of unit tests.

Popularity: 1% [?]

Written by hvolkmer

August 6th, 2009 at 6:52 am

Posted in Testing

Tagged with , ,

Technique for testing acts_as_* plugins

without comments

Introduction

Testing Rails plugins has always been a pain, until the dry_plugin_test_helper came along. Now there is a difficulty with testing different calls to acts_as_* methods. For example, acts_as_list can be called in different ways. First, without any arguments, which means that there is an assumption that a column position exists which determines the order of the records; Second, the column can be made explicit; Third, a scope can be given, in which the order is presented. I am sure there are even more ways to call acts_as_list.

Our Technique

To test all of these calls, you’d need at least three different ActiveRecord classes as well as database tables for them, because usually an acts_as_* call does irreversible changes to a model class, such as including modules. Traditionally, the acts_as_* calls must be done before the test is run, usually in some file called abstract_unit.rb.

To get around this limitation, we’d like to present our simple solution to this problem, where you can reuse the same ActiveRecord class with the same table for multiple calls to acts_as_* methods, without the different calls interfering with each other.

(The following code assumes you use Test::Unit. Replace the setup method with the before block if you use RSpec)

Using dry_plugin_test_helper, you always have a simple model class Article defined (if you dont use dry_plugin_test_helper, the you can easily define your own model class). For the sake of illustration, we use this Article model class in the following code. First, we add a line to the setup method to remove the Article class from the object space like this:


def setup
  Object.send :remove_const, :Article if Object.const_defined?(:Article)
  # ...
end

The if part is neccessary, since the first time this line is executed, Article might not exist yet.

After this line, we have to redefine Article, such that we can start using it in our test cases:


def setup
  # ...
  Object.const_set(:Article, Class.new(ActiveRecord::Base))
end

This initializes an empty ActiveRecord subclass and assigns it to a global constant called Article. This Article constant can now be used to test your calls to your acts_as_* method.

Example

For the following example, we use the fictious acts_as_hasselhoff plugin.


class ActsAsHasselhoffTest < Test::Unit::TestCase
  def setup
    Object.send :remove_const, :Article if Object.const_defined?(:Article)
    Object.const_set(:Article, Class.new(ActiveRecord::Base))
  end

  def test_should_act_as_hasselhoff_without_parameters
    Article.acts_as_hasselhoff
    assert Article.looking_for?(:nothing)
  end

  def test_should_act_as_hasselhoff_with_explicit_parameter
    Article.acts_as_hasselhoff :looking_for => :freedom
    assert Article.looking_for?(:freedom)
  end
end

With the setup method, the two calls to acts_as_hasselhoff do not interfere with each other, not even when the acts_as_hasselhoff includes modules to the calling class (what most acts_as_* plugins do).

As an added plus, you can even use mocha or some other mocking framework to mock parts of your calls to acts_as_hasselhoff, to make sure that the correct execution paths are chosen. Of course, then the model might not act as the real Hasselhoff, but we don’t care about that, because the next test gets a fresh new Article class that acts as nothing at all.

Making things prettier

Having these complicated and hacky metaprogramming calls in your setup method is kinda ugly. So lets take them out and put them in our test_helper.rb:


class Test::Unit::TestCase
protected
  def reset_active_record_class(name)
    Object.send :remove_const, name if Object.const_defined?(name)
    Object.const_set(name, Class.new(ActiveRecord::Base))
  end
end

Now, we can reset any ActiveRecord model to an empty class whenever we want inside our tests. The simplified setup method now looks like this:


def setup
  reset_active_record_class(:Article)
end

That’s it

That’s how you can test acts_as_* plugins. Enjoy!

Popularity: 1% [?]

Written by tkadauke

February 1st, 2009 at 6:04 pm

Posted in Development

Tagged with , ,

dry_plugin_test_helper gem released

without comments

For the impatient

What is it?

Imagine you have some fancy acts_as_something plugin and, of course, you want to test it. How do you do it? In the Rails app you are developing it for? This could lead to longer environment load times and this is hardly testing in isolation. Creating a rails app just for testing the plugin? That’s better but creating a rails app for every new plugin – that’s so un-DRY! And you cannot test the plugin on its own. You could ship the bare rails app with your plugin but again: not DRY and lots of code you don’t really need for your plugin.

dry_plugin_test_helper to the rescue!

What it does

The gem sets up the test environment which means you have a stub rails app with your plugin and the following models:

  • Article: belongs_to :author, has_many :comments
  • Author: has_many :articles
  • Comment: belongs_to :articles, belongs_to :user
  • User: has_many :comments

The models will be added to a sqlite in memory database for fast testing.

To use the gem enter the following lines in your test_helper.rb or abstract_unit.rb (or however you may call it):

1
2
3
4
require 'rubygems'
require 'dry_plugin_test_helper'

PluginTestEnvironment.initialize_environment(File.dirname(__FILE__))

You can add your own test models using a migration in your test directory like
this:

1
2
3
4
5
6
7
8
 PluginTestEnvironment::Migration.setup do 

   create_table "animals", :force => true do |t|
     t.column "name", :string
     t.column "age",  :integer
   end

 end

If you don’t want the standard models you can initialize the test environment
like this:


PluginTestEnvironment.initialize_environment(File.dirname(__FILE__), :use_standard_migration => false)

How it works

The gem contains a stripped down rails directory structure and boots up this rails environment and then adds the plugin under test to this environment. It uses the sqlite3 in memory db for faster testing.

Caveats

You can really only test the plugin that you are testing. If your plugin has some dependencies to other plugins (why should it?) you cannot test it using this gem out of he box. You’d have to mess with the load path yourself (I haven’t tried it)

Todo

  • support for RSpec and other testing frameworks (might already work – haven’t tried it)
  • Automatic Rails version discovery
  • Clean up / strip down rails env to bare minimum (It’s not completly clean yet)

Dependencies

The dry_plugin_test_helper gem depends on Rails and sqlite3-ruby

Getting it, License and Patches

Get the complete source code through Github. License is MIT. That means that you can do whatever you want with the software, as long as the copyright statement stays intact. Please be a kind open source citizen, and give back your patches and extensions. Just fork the code on Github, and after you’re done, send us a pull request. Thanks for your help!

Popularity: 1% [?]

Written by hvolkmer

July 7th, 2008 at 7:13 pm

Posted in Open Source Releases

Tagged with , ,