The Frontier Group - Blog

Using RSpec Example Groups for Common Functionality

January 13th, 2010, by aaron

I’m currently getting into using RSpec for testing our controllers on what is turning into a large project. It’s been more than handy because we have a lot of complex scoping to take into account whenever retrieving data. People don’t like to see other peoples’ financial data, mostly because it implies that someone is probably looking at theirs. With this in mind it’s more than important that we know the right data is going to the right places and hence the need for controller testing.

Now most of our controllers require the user to be logged in so writing tests to check this for every controller is annoying and time consuming, more than that it feels dirty. I think this is what some people call a code smell though I’m not up to speed on buzz words. There are also other tasks that are done quite often such as setting up the various types of users we’d like to test as, it would be nice if this were easily put in one place and could be easily pulled in. I guess I was looking for a template of tests that I could share.

It seems that the solution to it is found in Shared Example Groups which I hadn’t heard very much discussion about and it kind of leaves working out how they work to you rather than documenting it too much.

So far I’ve used it simply to make sure that controllers that require are redirecting users appropriately and also for setting up a specific type of user for our system before testing.

I created a directory under /spec/support called example_groups and in there I have a file called login_groups.rb. In that file I have something like the following :

shared_examples_for "customer is logged in" do
  before(:all) do
    @user = Factory(:customer_user)
    @user.customers.push Factory(:customer)
  end

  before(:each) do
    activate_authlogic
    OperatorSession.create(@operator)
  end
end

Now in my spec files when I have a bunch of tests requiring a logged in customer I will include this little snippet :

  it_should_behave_like "customer is logged in"

I get a logged in customer to start playing around with. I have the spec/support/example_groups directory in my include paths for Rspec and so it just all works.

My tests can then start to look like :

describe MerchantsController do
  it_should_behave_like "areas requiring login"

  context "customer logged in" do
    it_should_behave_like "customer is logged in"

    ... insert other tests here ...
  end
end

It means I can swap in another authentication gem/plugin pretty easily and also encapsulates the logic about creating customers, or whatever type of item you want to use, so that if that changes you can swap things in and out with a minimum of fuss.

Just to be clear, example groups aren’t limited to setup tasks or connecting to before/after hooks, you can also include a bunch of tests as well. This allows me to have a bunch of tests to run to make sure that a user does have to be logged in for various controllers and include these tests in on line.

I hope this helps someone, it took a bit of searching and trial and error myself this morning to get it working and find the uses for it that I’ve found. I’m definitely open to better solutions to this sort of issue though.

We are a web development company and this is our blog. We specialize in building web applications with the Ruby on Rails framework. You can read more about our Ruby on Rails development or contact us.


Testing File Uploads with Webrat and Paperclip

June 10th, 2009, by aaron

I wanted to integrate some branding functionality into an application we’re developing and so I needed test file upload functionality. We’re using Webrat for integration tests, though this will likely change as we increase the amount of Javascript in the app. I added Paperclip to handle the file attachments for logos, and everything was working.

When I added validation to the model, making sure that the file being attached was an image, this broke the tests. It didn’t seem to matter what type the file was, it would fail no matter what on the file type validation.

I used ruby-debug to debug my test and it seems by default Webrat sends file uploads as plain text. It does have the option to specify the file type when attaching the file, so the easiest way around this is just to specify the MIME type for the file. Now my Cucumber step looks something like this :

When /^I attach "([^\"]*)" image to the "([^\"]*)" file field$/ do |filename, field|
  type = filename.split(".")[1]

  if type == "jpg"
    type = "image/jpeg"
  end

  attach_file field, File.join(RAILS_ROOT, test_asset_path, filename), type
end

Obviously this will need some work as I progress, but it works. At this stage I have an assets folder in my features folder to store any files that I need for my tests.

On the confirmation end of the test I just have a simple tag test to check that the image tag is displaying, and it contains the correct src attribute :

Then /^I should see tag "(.+)"$/ do |selector|
  (Hpricot(response.body)/selector).should_not be_empty
end

So in my feature test I have :

Then I should see tag "img[@src*='']"

This just confirms that there is an image tag that contains the file name of the file that I uploaded in the test.

We are a web development company and this is our blog. We specialize in building web applications with the Ruby on Rails framework. You can read more about our Ruby on Rails development or contact us.


Making a Copy of an Object in PHP

February 5th, 2009, by aaron

In PHP4 objects were passed by value, it’s probably the intuitive way to deal with variables for a beginner and in a language where objects are not first class. However in PHP5 this has been changed and now objects are passed by reference, this stung me when writing some tests recently.

public function testNameIsUnique() {
	$test1 = $this->BuildValidDiscountType();
	$test2 = $test1;

	$test1->Save();
	$this->assertTrue($test1->id > 0);

	$this->setExpectedException('DiscountTypeException');
	$test2->Save();
}

This code shouldn’t have worked as far as I was concerned, in fact I was expecting an exception to be raised. Instead it was working and after a little debug tour I found that my $test1 = $test2 line was causing $test2 to be a reference to $test1, not what I wanted. This caused my update method to be triggered instead and of course the name is still unique.

It only required a small change to that line, using the clone specifier :

$test1 = clone $test2;

After that everything went as expected and I knocked off another test, and added to my PHP knowledge.

We are a web development company and this is our blog. We specialize in building web applications with the Ruby on Rails framework. You can read more about our Ruby on Rails development or contact us.


Follow Us

Stay in the Loop

  • Enter your email address to subscribe to our mailing list. You'll get updates about our products, specials and bonus offers, and general behind the scenes news from our team.

Twitter

Newsletters

Alexa Rank

Testimonial

The boys at The Frontier Group are amazing! For such a relaxed and personable organisation, they have phenomenal technical ability and a rampant professionalism. They have customisable solutions for all of my IT needs and they always deliver, on time and beyond expectation.

They fix problems other service providers can't and they helped me get a critical section of my web site up and running 10 minutes after I emailed the request!

Alex Hyndman, Nexus Car Share.

Featured Project

Case Study - Caudo Group - www.caudo.com.au

Website

www.caudo.com.au

Caudo Machinery

Caudo Group engaged our services to redesign their outdated website. We sent our photographer on-site to capture the essence of their business and turned it into a stunning web design.