I was recently tasked with this story:
Background:
Given I go to the sign up page
And I fill in "Email" with "new@example.com"
And I fill in "Password" with "password"
Scenario: Visitor signs up and does not want email
When I press "Sign up"
Then email service is not notified "new@example.com" signed up
Scenario: Visitor signs up and wants email
When I check "Please email me"
And I press "Sign up"
Then email service is notified "new@example.com" signed up
The email service in question was internal, accessible via an HTTP API, and did not have a Ruby client library.
So, I had to write and test my own. The usual approach would involve using a tool like Sham Rack or Artifice to stub and record the HTTP requests. I decided to try something different and see how it felt.
First, I needed an interface that I could test:
Then /^email service is notified "([^"]*)" signed up$/ do |email|
EmailService.notifications.should include(email)
end
Then /^email service is not notified "([^"]*)" signed up$/ do |email|
EmailService.notifications.should_not include(email)
end
I’m re-using a pattern (“store data in a simple array for easy state-based testing”) we’ve used before for Javascript integration testing Mixpanel and the AjaxRecorder (which was roundly boo’ed as a bad idea).
Cool, I have the start to an EmailService interface. I thought I wanted it invoked as part of an after_save callback on the User model, so here’s that spec:
describe User, "who opts into email" do
subject { Factory.build(:user, :email_opt_in => true) }
before do
EmailService.stubs(:notify)
subject.save
end
it "notifies EmailService" do
EmailService.should have_received(:notify).with(subject.email)
end
end
describe User, "who does not opt into email" do
subject { Factory.build(:user, :email_opt_in => false) }
before do
EmailService.stubs(:notify)
subject.save
end
it "does not notify EmailService" do
EmailService.should have_received(:notify).never
end
end
This is the stubbing and spying technique and uses RSpec, mocha, and bourne.
My thought process was that I needed an active verb, notify to invoke when the user is created, but that will store the invocation in a notifications array that the Cucumber step definition needs to check state (I don’t want to stub, spy, or mock in an integration test).
So, making the user spec pass isn’t bad:
require 'email_service/notifier'
class User < ActiveRecord::Base
after_create do
EmailService.notify(email) if email_opt_in?
end
end
Now, the EmailService can be spec’ed. We already had John Nunemaker’s HTTParty as a dependency in the app, and I only had to make one HTTP POST, so I knew I would be re-using HTTParty’s interface.
describe EmailService::Notifier, "#post" do
subject { EmailService::Notifier }
let(:email) { "new-signup@example.com" }
before do
subject.stubs(:post)
subject.new(email).post
end
it "POSTs to email service with API_KEY and given email" do
subject.should have_received(:post).with(
subject::URL, :query => { :api_key => subject::PARAMS, :email => email }
)
end
end
What I care about here is that during the one POST the app has to make, that the parameters are correct. This is close to hitting the live service as I’m willing to get without making an HTTP request.
I had an internal debate with myself while writing it over whether this is “stubbing the system under test” (considered bad practice). I decided “no” because despite the subject being stubbed, the system under test is actually the EmailService::Notifier#post method.
The stubbed and spied method is also mixed in from HTTParty, so I feel clean with this approach.
Making it pass:
require "httparty"
module EmailService
class << self
attr_accessor :notifications
end
def self.notify(email, live = false)
if Rails.env.production? || live
Notifier.new(email).post
else
self.notifications << email
end
end
class Notifier
include HTTParty
URL = 'http://emailservice.example.com'
API_KEY = 12345
def initialize(email)
@url = URL
@email = email
end
def post
self.class.post(@url, :query => { :api_key => API_KEY, :email => @email })
end
end
end
EmailService.notify, which is used by the User model.EmailService.notify with the live flag so I can invoke it from the Rails console on production or staging when testing or debugging.This almost takes longer to describe than to code but I’m curious what people think about this style of writing an API client with test, staging, and production environments in mind. How do you do things differently?
Today, we’re excited to announce the launch of one of the most requested new features for paid Hoptoad accounts, and one we’ve been really looking forward to ourselves since we rolled our paid accounts for Hoptoad in December—Integration with Lighthouse.
This new feature allows you to seamlessly associate errors in Hoptoad with an existing ticket in your Lighthouse project, or to create a new ticket for the problem, all from within Hoptoad itself.

Creating a ticket for Lighthouse from Hoptoad

This error in Hoptoad has been associated with a Lighthouse ticket

This Lighthouse ticket links back to the Hoptoad error.

Searching for an existing ticket in Lighthouse to associate with this error.
If you have a paid Hoptoad account, at any level, this feature is available to you now. Directions for setting it up can be found on the hoptoad tender site.
Having worked with other applications that integrate with Lighthouse, we’ve been frustrated with the fact that it only allows you to supply the Lighthouse API token for one user, and then all activity in Lighthouse appears as though that one user performed it. This is fine for a basic level of use, but really gets hard to follow if you’re a heavy lighthouse/ticketing user and rely on the identities behind each account mapping to real world clients and developers that you also email and talk to on the phone.
To address this, we thought it was important that the Hoptoad integration with Lighthouse accept an individual API token for each user in your Hoptoad account. That way, when someone uses Hoptoad to create a new ticket, or associate with an existing one, it shows up in Lighthouse as the actual person who performed it.
When an error comes into hoptoad, you were already able to “resolve” it, but that was about it. Sometimes that’s fine, but often times we found ourselves wanting to discuss the ticket with other developers, or have some better way to communicate with clients about an issue with their application.
We’ve often gotten the suggestion to add simple commenting on errors in Hoptoad, to facilitate this discussion, and have resisted. We feel pretty strongly that we don’t want Hoptoad to become a bug tracker, and adding comments to the errors would send us straight in that direction. So, instead, with this Lighthouse integration, we’ve set a clear demarcation point.
Now, when an error comes into an account with lighthouse support enabled…
If you’re the developer of a project management system or bug tracking system that you’d like to integrate with Hoptoad, please get in touch with us.
I log a lot of friggin’ time on Basecamp. We all track our time incessantly here; for client work, product development, R&D, conference calls, whatever. This means I spend a lot of time logged into Basecamp, with my browser up, typing in times and tabbing between form inputs.
UNTIL RECENTLY!!!
While I wouldn’t call myself a command line “junkie”, I have grown to appreciate the brevity with which I can make great and terrible things happen by using it. Since Basecamp has an API, and since DHH was even kind enough to make a Ruby wrapper around it, there’s no reason I couldn’t make a tiny little command line time tracker.
SO THAT’S WHAT I DID!!!
The syntax is pretty simple, and is explained in detail on the README, but the short of it is that after you give it your Basecamp credentials, you can specify how much time for each message, or use a start/stop timer so that you don’t have to keep track of the time. A few brief examples:
# Log 1.5 hours of time to the default project
track log 1.5 "How I spent this time"
# start tracking time for the "Roller Derby" project
track start rol
# stop tracking time
track stop "Constructed the roller derby foundation"
Right now, me and two other folks at thoughtbot prefer the command line to a big webpage for entering time, and use it all day every day. I finally threw it up on Github. This isn’t a thoughtbot project, so it’s under my account there.
Since it’s up on Github, you can install it as a gem:
gem sources -a http://gems.github.com
sudo gem install Klondike-basecamper
HEY BUT ALSO!!!!!
If you’re already using source control via the command line, like svn or git, there’s no reason you can’t hack together a script that commits your code and uses the same commit message to log your time, simultaneously. It would probably look something like this. That’s what I use, and it’s such a hack, but it lets me commit code with commit -l 'message'. That’ll run an svn commit on all files with that message, stop the timer and log time with that message. If I use -ls instead of -l it’ll start the timer again, meaning I can just commit -ls all the day, and my time gets logged.
AND BY ALL MEANS FORK IT!!!!