Blog


Nov

Our Presentations at RubyConf 2010


Two weeks ago, Jonas and I were in New Orleans for the 10th annual RubyConf. This was my 2nd RubyConf, but I had a very different experience this time. This time I was one of the speakers. And I was giving two presentations.

The Front End Testing Frontier

One of the presentations was an extended version of the Front End Testing Frontier presentation I gave at Mountain.rb in October. This time I was fortunate enough to have my colleague Jonas Nicklas as a co-presenter. Jonas is the author of the testing libraries Capybara and Evergreen, our primary tools for JavaScript testing at Elabs.

I've uploaded the slides from the Front End Testing Frontier presentation, but they're pretty sparse. Video should be available in a few weeks, and I'll update this post then.

Socialist Software Development

My other presentation was titled Socialist Software Development. I came up with the title after seeing a clip from The Daily Show about socialism in Sweden. I saw some similarities between the principles of socialism and agile development, and since it seems most Americans are terrified by the mere mention of socialism, I thought it would be fun to go to the US and talk about it. The essence of my talk came from this passage from the British Labour Party constitution:

The Labour Party is a democratic socialist party. It believes that, by the strength of our common endeavour we achieve more than we achieve alone, so as to create, for each of us, the means to realise our true potential, and, for all of us, a community in which power, wealth, and opportunity are in the hands of the many, not the few.

While I drew some inspiration from my flippant title, I mostly talked about how Sharing is Caring, and how important that is in software development.

Giving such a "soft" talk was quite a bit harder than giving a technical presentation, but I was very happy with how it went. I've posted the slides for the Socialist Software Development presentation as well, and I'll update when the video is online.

What's Next?

I've been to a lot of conferences this year, and it's been great presenting at Mountain.rb and RubyConf. The next conference on our schedule is the Scottish Ruby Conference in April next year. All the Elabs developers will be there, and I'm really looking forward to that. Then there's our own conference, Nordic Ruby, in June. This year was amazing, and it looks like the one next year will be even better.

I don't have any confirmed speaking events for next year, but I would love to do a couple and continue to improve as a speaker. But I think I'll limit it to one presentation per conference. Giving two at RubyConf was a bit overwhelming.

Nov

Build, RubyConf and Dave Hoover


Today we are 4 people at the office, half of the crew. Jimmy and Johannes, our designers, left on Monday for Build which is a design conference in Belfast. And yesterday CJ and Jonas flew to RubyConf in New Orleans were they will be giving the talk: The Front End Testing Frontier. CJ will also give a talk about Socialist Software Development.

On Tuesday we had a short but very appreciated visit by Dave Hoover, who flew by Gothenburg to see us and join Got.rb in the evening. Early on Wednesday he continued his journey by train to Malmö and Øredev Developer Conference.

A quiet day at the office.

Sep

Speaking About Testing and Socialism at Mountain.rb and RubyConf


After attending and organizing it is finally time for the next step, to speak at a conference, two actually, with three talks. Dive in head first. CJ will be speaking at Mountain.rb and RubyConf.

First: Mountain.rb in Boulder, Colorado, October 6-8
The Talk: The Front End Testing Frontier

While most Ruby developers are very familiar with testing their code, frontend and JavaScript-testing is still a new frontier for many. This talk will show you how to easily write and run JavaScript integration tests with Capybara and Cucumber, and unit tests with Evergreen and Jasmine. The goal is to get you excited about frontend testing, and point you in the right direction to get started yourself!

Second and Third: RubyConf in New Orleans, November 11-13
Talk #1: The Front End Testing Frontier, extended, with co-presenter Jonas Nicklas
Talk #2: Socialist Software Development

Socialism is often portrayed as pure evil by US media (hello Fox News), yet many socialist countries are ranked as some of the best countries in the world (Newsweek). So maybe it's not all bad? If you look at job listings for software developers, it seem like a lot of companies are looking for "programmer rock stars", "coding ninjas", etc. There is a romantic notion about the ultra productive independent super developer. This talk examines software development from a socialist perspective.

Might we get better results and provide more value if we set aside our egos and work together?

CJ Kihlbom is speaking at Mountain.rb

Jun

Relieving the Pain of Controller Tests


Lately we've been embracing Cucumber as the preferred way of testing our Ruby on Rails applications. Cucumber is awesome, both for communicating with the customer and for getting thorough, full-stack tests of the application. We like Cucumber so much, we basically thought that it could replace both view and controller tests. It turns out we were wrong.

While our policy of Cucumber over view tests has been working out great so far, controllers are a different story. There is simply too much logic in the controller that is very hard to test (in a sane way) with Cucumber. It makes sense to have a cucumber feature that specifies that, for a non-admin user, a certain link should not be there, however that doesn't test the security of the application, despite the link not being there, the action may still be freely accessible for the user. Cucumber is not well suited (nor is it intended) to test these kinds of things.

But writing controller tests is a serious pain, so we tried to find a stack that felt natural and pleasant to work with. After some experimentation, we've settled on a slightly odd and interesting stack, consisting of the following:

  • Remarkable's descriptions and steps
  • RSpec's normal mocking syntax
  • Macro-style methods for different user contexts

We first tried using Remarkable on its own, but quickly found that we did not like the mocking syntax:

mock_models :data_point

describe(:post => :create, :data => "params") do
  expects :bulk_create, :on => DataPoint, 
          :with => proc { [@current_account, "params"] }, 
          :returns => proc { [mock_data_point] }

  it { should set_the_flash(:notice) }
  it { should render_template('data_points/new')}
  it { should assign_to(:data_points, :with => [mock_data_point]) }
end

The fact that it uses a "class-method" level for the DSL presents a lot of problems, it is impossible to simply use instance variables, methods need to be wrapped in procs, etc... It also, for some reason, does not seem to support stubs, which is very inconvenient in some cases. In the end we realized that there is absolutely no advantage to Remarkable's DSL over simply doing:

mock_models :data_point

describe(:post => :create, :data => "params") do
  before do
    DataPoint.should_receive(:bulk_create).with(@current_account, "params").and_return([mock_data_point])
  end

  it { should set_the_flash(:notice) }
  it { should render_template('data_points/new')}
  it { should assign_to(:data_points, :with => [mock_data_point]) }
end

One sore point though was that there was a lot of setup required in each controller spec for getting the logged in user right. We thought that with some block trickery we might be able to take care of this tedious setup:

module LogInContext

  def as_user(params={}, &block)
    describe "(as a logged in user)" do
      before do
        @current_user = mock('current_user')
        controller.stub!(:current_user).and_return(@current_user)
      end

      describe(params, &block)
    end
  end

  ...

  def deny_access_to_visitors(params={})
    as_visitor(params) do
      it { should redirect_to(new_session_path) }
    end
  end

end

Spec::Rails::Example::ControllerExampleGroup.extend(LogInContext)

Now we can use these contexts in our controller tests:

mock_models :data_point

as_user(:post => :create, :data => "params") do
  before do
    DataPoint.should_receive(:bulk_create).with(@current_account, "params").and_return([mock_data_point])
  end

  it { should set_the_flash(:notice) }
  it { should render_template('data_points/new')}
  it { should assign_to(:data_points, :with => [mock_data_point]) }
end

deny_access_to_visitors(:post => :create, :data => "params")

But we can do one better:

module LogInContext
  ...

  def as_user_only(params={}, &block)
    as_user(params, &block)
    deny_access_to_visitors(params)
  end
end

Now it is as simple as:

mock_models :data_point

as_user_only(:post => :create, :data => "params") do
  before do
    DataPoint.should_receive(:bulk_create).with(@current_account, "params").and_return([mock_data_point])
  end

  it { should set_the_flash(:notice) }
  it { should render_template('data_points/new')}
  it { should assign_to(:data_points, :with => [mock_data_point]) }
end

And this single test checks both that the post action is accessible to users, and also that it is not accessible to visitors. Of course these contexts can get a lot more advanced once different roles come into the picture. Here's something we're doing in our upcoming app KiNumbers:

module LogInContext
  ...

  def as_admin_or_user(params={}, &block)
    as_logged_in_user(params.dup, &block)
    as_admin(params.dup, &block)
    deny_access_to_visitors(params.dup)
  end

  def as_anyone(params={}, &block)
    as_admin(params.dup, &block)
    as_logged_in_user(params.dup, &block)
    as_visitor(params.dup, &block)
  end
end

This way there is no overhead in testing that a particular action is accessible to several different groups of users. Note that we had to call #dup on params, before passing it along, since Remarkable seems to use destructive operations on the Hash (it turned out to be empty after having been used in a describe block).

We ended up with a controller test that looks like this:

require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')

describe DataPointsController do

  mock_models :data_point

  as_admin_or_user(:get => :new) do
    it { should respond_with(:success) }
  end

  as_admin_or_user(:post => :create, :data => "params") do
    before do
      DataPoint.should_receive(:bulk_create).with(@current_account, "params").and_return([mock_data_point])
    end

    it { should set_the_flash(:notice) }
    it { should render_template('data_points/new')}
    it { should assign_to(:data_points, :with => [mock_data_point]) }
  end

end

Short, easy to read, yet also very thorough. Controller tests are sexy again! Spread the word!