1991-2016—25 years of Art & Logic

Factories, not Fixtures

Rosie the RiveterFor years, the most common way to provide test data for automated tests has been fixtures – hard-coded values, usually stored in text files.  For example, here’s some YAML-formatted data for a city model object:

- model: city
  fields:
    id: 1
    name: Los Angeles

In an environment like a Django app, this fixture would typically be loaded into a test database, and then accessed like: la = City.objects.get(id=1).

But fixtures and the frameworks that rely on them have several drawbacks:

Their data is brittle, especially when including references like unique IDs.  Changing or adding a property later may break tests.  This drawback also means that they are not easily modifiable, which tends to lead to duplicate fixtures with unwieldy names like los-angeles-with-an-extra-long-name.yaml.

They are typically loaded en masse by test frameworks like Django’s.  This can be slow if many unnecessary fixtures are being loaded for each unit test.  It also creates brittle sets of data.  For example, if an automated test is searching for objects with a matching city name and expects to find one instance, but later a new fixture is added that also matches, the test will fail.

Because fixtures are typically automatically loaded into a database by the test framework, it’s not particularly easy or fast to change the properties of an object for a single test case, which also tends to lead to an over-abundance of fixture files.

Factories, not fixtures

Test data factories solve these problems by making data and data loading more dynamic and programmable.  A factory is written in code, and while it can simply mimic a fixture by supplying default values for an object, factory libraries offer many other useful features.  Here’s a simple example factory:

Factory.define('city', City)
  .sequence('id')
  .attr('name', 'Los Angeles')

An instance of this factory could be created on the fly like: la = Factory.build('city').

Following the builder pattern, a factory generates data for all the attributes in its definition, constructs any necessary associated objects, and allows a test case to override these values.  Here’s a slightly more complex example:

Factory.define('city', City)
  .sequence('id')
  .attr('name', 'Los Angeles')
  // Define 'ref' as dependent on the id and name properties
  .attr('ref', ['id', 'name'], function(id, name) {
    return id + '-' + name;
  })

nyc = Factory.build('city', {name: 'NYC'})

Some typical features in factory libraries are:

  • integration with common ORMs; Factory.create(...) will typically build and save the object to a database
  • factory inheritance, allowing similar factories to share properties; e.g. Factory.define('city').extend('Olympic').attr('year', null)
  • lazy attributes; e.g. .attr('created_at', function() { return new Date(); })
  • associations to other factories

Factories across languages

Factory libraries have been springing up over the past handful of years.  Ruby’s factory_girl, which has been cloned to many other languages, was first released in 2008.  Several new ones for JavaScript and Objective-C have just appeared this year.

Here’s a list of factory libraries for a variety of common languages:

Test data for unit tests

A note of caution: a one line factory invocation may hide a great deal of complexity and database integration.  That may be fine for integration tests, but should be avoided for unit tests (see the blog post Factories breed complexity for a lengthier discussion).  Prefer to use simpler, non-persisted objects in unit tests.  Factory libraries may help here too by returning just the attributes as a hash or dictionary; e.g. factory_girl’s attributes_for method.

The Javascript Toolbox

http://www.flickr.com/photos/wwarby/5109516999/ by William Warby

http://www.flickr.com/photos/wwarby/5109516999/ by William Warby

Developers using JavaScript and HTML to build rich web apps are creating a plethora of tools to compartmentalize the common and organizational aspects of coding.  This burst of open source energy has led to new categories of libraries like the MV* frameworks, and multitudinous entries into others, like template engines.  Which leads to a problem: how does one keep up with the ever-shifting set of possibilities? (more…)

I Hear the Train a Comin’ – A Few Reasons Why Rails 4.0 Will Rock Your World

rails4Mention Rails, and you will often believe you are debating White Castle burgers. You either love or hate it with little room for anything in between. DHH created a framework where you generally have to play by his rules and if you disagree with those rules, you might become frustrated or a bit disgruntled while working in the framework.

Whether you are comfortable working within DHH’s framework or not, the fact is that the train is moving and it includes new features that will improve your apps as the version matures. Developers using Rails will cringe at points similar to what we felt with the introduction of the asset pipeline. Even tonight, as I write this post, I have had a moment of asset pipeline cringing. Hating the change… or as DHH puts it, the “progress”…

However, there are numerous advantages to using Rails and the newest installment will build on and create new features that will make development easier, more secure, and more fun (at least we hope in the long run). (more…)

Debugging Ruby on Rails…as a C++ Developer – Part II

200px-Ruby_on_Rails.svg

The intent of this article is to approach development and debugging of Ruby on Rails applications from the perspetive of a C++ developer. In Part I I discussed some of the fundamental differences between Ruby on Rails and C++ development.

I started a simple “blog with comments” example to step through and showed how to use the ruby console to debug the model and what some of the exception messages returned to the view are telling us.

Where are the exceptions?

While we know the model is right (we debugged it already) sometimes there is no exception information being displayed. Where do we turn then? In this part of the article I am going to expand on our example and go deeper into what to look for there are no meaningful exception messages.

(more…)

Debugging Ruby on Rails…as a C++ Developer – Part I

200px-Ruby_on_Rails.svgQuick background

If you already know why C++ and Ruby on Rails are fundamentally different and just want to see the example, you can skip to The Example.

I’ve been developing software for many years but, for the most part, have stayed in the C++ world. I made the transition to web applications development with C# ASP.NET MVC applications, which I felt is a fairly easy transition. Adjusting to the MVC design pattern took a little change in thinking but it’s not a terribly difficult pattern to understand. It’s been a few years now and I am quite comfortable in that world.

C++, and its garbage-collected baby brother C#, are straight-forward. There is very little magic involved. If you know the language, the ASP.NET MVC platform all just kind of makes sense. It does exactly what you tell it to do. If you understand C# (and to some extent HTML and JavaScript), you’re 90% of the way to understanding ASP.NET MVC.

Ruby on Rails is different. Very different. (more…)

Contact Us