I recently wrote a Ruby client for Amazon Alexa’s APIs, and thought I’d
pull out an example of nice, simple dependency injection to facilitate unit
testing. Nothing revolutionary or complicated, just good practice.
The example is based around a UriSigner class, normally used by the calling
code like this:
UriSigner.new(*credentials).sign_uri(uri)
The calling code doesn’t know or care that UriSigner depends on Base64,
OpenSSL::Digest::SHA256 and OpenSSL::HMAC. The unit test for
UriSigner, however, cares for two reasons.
Firstly, they’re external dependencies, and only need to be tested for correct
usage, not correct implementation.
Secondly, these dependencies represent an encoder and a cryptographic hash
function; they’re deterministic, but they return very opaque data which can
make tests and their failure messages difficult to understand.
So instead of testing against magical (computed in advance) Base64 strings and
HMAC hashes, I’ve used simple attr_writer dependency injectors:
The unit test can then inject MiniTest::Mock instances in place of the
real Base64 and HMAC implementations, setting expected method calls and their
return values:
As simple as that.
The same approach is used by the HTTP Client class to stub out actual HTTP
calls via Net::HTTP. There’s great libraries like VCR, WebMock and
FakeWeb for handling this, but sometimes it’s easier to keep it lo-fi:
This kind of dependency injection is one of many basic techniques which aren’t
fancy enough to get a lot of press, but go a long way to keeping your objects
and tests in order.
Got any thoughts? Hit me up, I’m @pda on Twitter,
where I generally write about this kind of thing.
paul@paulbookpro ~/project ⸩ time rspec spec/lib/method_hunting_delegator_spec.rb
..
Finished in 0.00078 seconds
2 examples, 0 failures
rspec spec/lib/method_hunting_delegator_spec.rb -f d 6.76s user 1.64s system 91% cpu 9.225 total
Holy crap, that’s 9 seconds of Rails startup, for 0.00078 seconds worth of
RSpec. And this class/test doesn’t even use Rails! We can do better.
The culprit? That require "spec_helper" at the top of every spec file which
loads the entire of Rails:
# This file is copied to spec/ when you run 'rails generate rspec:install'
ENV["RAILS_ENV"] ||= 'test'
require File.expand_path("../../config/environment", __FILE__)
require 'rspec/rails'
require 'rspec/autorun'
# etc ...
There’s a few ways to deal with this, each with their own pitfalls. After
trying many approaches, I’ve settled on a tiered RSpec initializer
(spec_helper.rb and friends) which I can choose when invoking RSpec.
All the spec files still require "spec_helper", but it looks more like this:
Which means we can select different initializers using the SPEC environment
variable. The following spec_helper_unit.rb is perfect for the
method_hunting_delegator_spec which took 9 seconds earlier, because there’s no
dependencies on Rails.
The result?
paul@paulbookpro ~/project ⸩ time SPEC=unit rspec spec/lib/method_hunting_delegator_spec.rb
..
Finished in 0.00079 seconds
2 examples, 0 failures
SPEC=unit rspec spec/lib/method_hunting_delegator_spec.rb 0.81s user 0.08s system 99% cpu 0.890 total
Under a second (0.890) is much more like it, and we still get class autoloading
provided by ActiveSupport. I use this mode for just about everything except
subclasses of Rails components, and those I keep a slim as possible. Moving
logic into SOLID classes is something you’ll benefit from anyway, and
these faster tests provide extra incentive. This example was a spec for a
standalone class living in RAILS_ROOT/lib/ but I use it for all sorts of
classes under app/models/, app/presenters/, app/forms/ etc.
But this zero-Rails initializer doesn’t help with testing your ORM-subclasses
(we’ll begrudgingly call them “models”) which depend on ActiveRecord:
And having tasted sub-second tests, 12 seconds is clearly unacceptable:
paul@paulbookpro ~/project ⸩ time rspec spec/models/book_spec.rb
.................
Finished in 0.67016 seconds
17 examples, 0 failures
rspec spec/models/book_spec.rb 8.08s user 1.85s system 78% cpu 12.698 total
But if you write your classes carefully, they don’t need to depend on much
from Rails except ActiveRecord. So let’s write a spec_helper which loads &
configures ActiveRecord, plus a few other bits and pieces useful for testing
database-persisted models.
You’ll have to excuse the Devise hackery; it was the one component tightly
coupled into a model (User), and like most Rails app, that particular model
is at the center of the whole relationship graph. Perhaps there’s a better
solution, but this got me fast model tests for all but the user_spec itself.
Lets run that model spec again, this time boosted by SPEC=model:
paul@paulbookpro ~/project ⸩ time SPEC=model rspec spec/models/book_spec.rb
.................
Finished in 0.58512 seconds
17 examples, 0 failures
SPEC=model rspec spec/models/book_spec.rb 6.50s user 0.21s system 98% cpu 6.844 total
Note that your model classes can still depend on external gems, but they’ll
need to e.g. require "money" at the top. I suspect this explicit declaration
of dependency isn’t a bad idea anyway.
Of course, there’s always going to be specs which depend on the whole stack,
such as acceptance tests. For those, here’s the default spec_helper_full.rb;
basically like the original spec_helper.rb:
I was implementing search in a Ruby app where the results objects were instances
of a mix of model classes. Each one had what could be considered a title and a
description, but the method names were inconsistent.
Wrapping each result in a SearchResult decorator to normalize the interface
seemed like a good idea. Ruby provides an abstract Delegator and a concrete
SimpleDelegator which gets most of the way there.
To normalize the method interface, I wrote an extension of SimpleDelegator
with a #hunt_and_call(*candidates) method, which finds and calls the first
method of the candidate list which the delegate responds to.
Here’s the example calling code:
And the MethodHuntingDelegator implementation:
And of course:
Completely insane? Useful enough for a gem? Better way of going about it? Give
me hell in the gist comments.
Ridiculously good article on digital cameras at The Verge, worth reading
even if you’re not in the market for one.
What we’re seeking to do here is help you make an informed decision by
separating the meaningful data from the meaningless. This is a guide to
discerning the things that will make a recognizable difference in your
photographic experience and results. We’ve selected a few of our favorite
cameras in the categories below, but those will change over time, whereas the
rest of this advice will (hopefully) remain relevant for a long time to come.
Why can’t there be more content of this quality on the Internet?
It works like you’d expect, with a couple restrictions: First, every morning it starts over fresh. Your list from the day before is thrown in the trash. This, hopefully, will encourage the completion of all tasks each day and discourage the addition of frivolous items. Second, there’s no reordering. I want to trust my subconscious; if I add a task before another, then it’s because my mind has determined it’s priority by remembering it sooner.
An excellent OpenGL tutorial; beware other documentation and tutorials which endorse deprecated APIs and practices.
Modern enough to be applicable to OpenGL ES 2.0 (and therefore WebGL), which requires vertex and fragment shaders to be written in OpenGL Shader Language to take advantage of the programmable rendering pipeline, and which removes much of the procedural (glBegin/glEnd) API.
Adapting this tutorial to Cocoa Touch for iPhone/iPad OpenGL ES 2.0 development was relatively easy, and beat any iPhone OS specific documentation for ES 2.0 that I’ve found.
Nice simple template format, implementations in Ruby, Python, JavaScript, PHP and more.
Similar to Django templates in simplicity, syntax and sensible constraint of logic.
Tiny blog engine in Ruby and Rack, uses flat git-managed content files containing YAML & ERB/Markdown, handles comments via disqus, leaves caching to HTTP.