lesscode.org


'Languages' Archives

Fun with Fixtures  2

Cat.: Ruby, Rails
25. September 2005

My favorite part of Agile Web Development with Rails is the section on testing. I’ve found the framework around testing included with Rails to be a wonderful blend of simplicity and power and this chapter in the book is the perfect compliment. It’s based largely on the core Ruby Test::Unit module but adds some important features on top.

One of those features is Fixtures. Fixtures provide a simple, YAML-based file format for storing database state that should be loaded before test runs. The database is wiped and the fixtures are loaded before each individual test executes, providing consistent state for tests. See the section on fixtures in A Guide to Testing the Rails for more information. Here’s an example fixture from said section:

# low & behold!  I am a YAML comment!
david:
 id: 1 
 name: David Heinemeier Hansson 
 birthday: 1979-10-15 
 profession: Systems development

steve:
 id: 2
 name: Steve Ross Kellock
 birthday: 1974-09-27
 profession: guy with keyboard

The cool thing is that the top level fixture names (in this case, “david” and “steve”) become instance variables in your test case, allowing you to access fixture data in a very intuitively way from tests. The result of this is test code that reads like a story and is often almost humorous.

The book includes a sidebar with a little David head lamenting the importance of “Picking Good Fixture Names”:

Just like the names of variables in general, you want to keep the names of fixtures as self-explanatory as possible. This increases the readability of the tests when you’re asserting that @valid_order_for_fred is indeed Fred’s valid order. It also makes it a lot easier to remember which fixture you’re supposed to test against without having to look up p1 or order4. The more fixtures you get, the more important it is to pick good fixture names. So, starting early keeps you happy later.

But what to do with fixtures that can’t easily get a self-explanatory name like @valid_order_for_fred? Pick natural names that you have an easier time associating to a role. For example, instead of using order1, use christmas_order. Instead of customer1, use fred. Once you get into the habit of natural names, you’ll soon be weaving a nice little story about how fred is paying for his christmas_order with his invalid_credit_card first, then paying his valid_credit_card, and finally choosing to ship it all off to aunt_mary.

Association-based stories are key to remembering large worlds of fixtures with ease.

Taking this advice, I started in on testing a part of an application I’m working on now. The result is worth posting in it’s entirety (hint: it gets interesting towards the middle):

require File.dirname(__FILE__) + ‘/../test_helper’

class EnrolleeTest < Test::Unit::TestCase
  fixtures :coverage_types, :plans, :coverages, :plan_levels, :ppo_options,
           :elections, :enrollees, :enrollments, :tpas, :tpas_users, :users,
           :roles

  def setup
    @joe = Enrollee.find(@joe_the_policy_holder.id)
    @rita = Enrollee.find(@rita_the_spouse.id)
    @billy = Enrollee.find(@billy_the_dependent.id)
    @alice = Enrollee.find(@alice_the_dependent.id)
    @the_family = [@joe, @rita, @billy, @alice]
    @enrollment = Enrollment.find(@test_enrollment.id)
  end

  
  def test_common_attrs
    @the_family.each do |enrollee|
      assert_kind_of Enrollee, enrollee
      assert_equal @enrollment.id, enrollee.enrollment_id
      assert_equal @enrollment, enrollee.enrollment
      assert_equal @joe.id, enrollee.policy_holder_id
      assert_equal @joe, enrollee.policy_holder
    end
  end

  def test_get_gender
    assert_equal :male, @joe.gender, "Joe is a male"
    assert @joe.male?, "Joe is a male"
    assert_equal :female, @rita.gender, "Rita is a female"
    assert @rita.female?, "Rita is a female"
    assert !@billy.female?, "Billy is not a female"
    assert !@alice.male?, "Sally is not a male"
  end

  def test_set_gender
    [:female, ‘F’, 2].each do |tok|
      @joe.gender = tok
      assert_equal :female, @joe.gender, "Joe is now a female"
      assert @joe.save, "Joe could not be saved after sex change"
      @joe.reload
      assert_equal :female, @joe.gender, "Joe is now a female"
    end

    [:male, ‘M’, 1].each do |tok|
      @rita.gender = tok
      assert_equal :male, @rita.gender, "Rita is now a male"
      assert @rita.save, "Rita could not be saved after sex change"
      @rita.reload
      assert_equal :male, @rita.gender, "Rita is now a male"
    end

    # make sure that we can set it to nil
    @joe.gender = nil
    assert_equal nil, @joe.gender
    assert @joe.save(false), "Joe couldn’t be saved after neutering…"
    @joe.reload
    assert_equal nil, @joe.gender

    @joe.gender = ‘’
    assert_equal nil, @joe.gender
    assert @joe.save(false), "Joe couldn’t be saved after neutering…"
    @joe.reload
    assert_equal nil, @joe.gender
  end

  def test_marital_status
    assert_equal :married, @joe.marital_status
    assert @joe.married?, "Joe is married"
    assert !@joe.single?, "Joe is not single"
    assert @billy.single?, "Billy is single"
    assert !@billy.married?, "Billy is not married"
    assert_equal :single, @billy.marital_status
  end

  def test_set_marital_status
    [:married, 2].each do |tok|
      @billy.marital_status = tok
      assert_equal :married, @billy.marital_status
      assert @billy.save, "Billy could not be saved after he got married"
      @billy.reload
      assert_equal :married, @billy.marital_status
    end

    [:single, 1].each do |tok|
      @rita.marital_status = tok
      assert_equal :single, @rita.marital_status
      assert @rita.save, "Rita could not be saved after her divorce"
      @rita.reload
      assert_equal :single, @rita.marital_status
    end
  end
end

:)

lesscode … more docs?  21

Cat.: Ruby, PHP, First they ignore you.., Rails
20. September 2005

I’ll take it as a given that if you’re reading this then you agree that, for the sake of sanity and productivity, it’s time coders gave up on roll-your-own, and moved over to modern frameworks where one can concentrate on business logic rather than request parsing (and get all those AJAX goodies for free ;-) ).

I’ve been looking on with interest for the last year and a bit, and as I’ve watched the pioneers blaze their XP, RoR, lesscode trail across the web-firmament, I’ve begun to suspect that I must have missed something. Yes, it’s powerful stuff, and yes it isn’t all smoke and mirrors - there really is “gold in them thar hills…” - but, and for me it’s a big but, we seem to be missing the big picture. Where are the map makers? Where’s the documentation for the second (or third) wave?

Self-documenting code is all very well, and having a common vocabulary of design patterns helps when discussing solutions to individual problems. But what second-wavers really need (and I include myself here - no, actually, put me down as a third-waver) are more pictures. More exposition. Road maps.

Is there a way to add XD (eXtreme Documentation?) back into the XP mix? Writing elegant code is hard, and people who do it earn the admiration they received. But I would argue that writing good documentation is harder, and that it shouldn’t be left for the second-wavers to do.

People who’ve moved to XP have already gone thorugh the pain barrier of

  • write the tests
  • then write the code
  • (then refactor)

and have proved that in the long run, it means better code, less debugging, in less time. But having proved that that works, might there be some benefit in switching to;

  • write the spec
  • then write the tests
  • then write the code
  • (then refactor)
  • then write an overview!!!

Might this result in (my h-nought) more easily modfied code, quicker adoption by other coders, greater community support?

I’m genuinely interested in other people’s views on moving documentation down(?) the food-chain, so that it’s non-optional, and as integral to writing new code (and frameworks) as writing good tests. Yes, there are good auto-doc tools and methodologies out there, but that right now they still seem to be seen as secondary to the process by Joe Frontiersman, and they only deal with what’s in the file, not what’s in the coder’s/architect’s head. (There’s the nine diagrams of UML, yes, but who on the bleeding-wrist of open-source technology is actively using/sharing designs via UML?)

Let me know if I’ve missed a trick somewhere.

[A few thoughts for the pot: I believe the that the reason the Open Source model works because it’s based on non-coercive collaboration. But Source Forge is littered with unfinished, half-baked projects because someone didn’t think to check that there wasn’t already a project out there that they could use. (How many PHPUnits does the community really need?) Should there be a ‘requirement’ for documentation before a project gets listed? Perhaps it’s time for ‘ideaforge’, or ‘architectureforge”?]

YAPWF! Brand new! Or is it?  5

Cat.: Python
17. September 2005

Rather than reinventing everything or trying to clone some other framework, TurboGears takes advantage of the great tools that are already available!

The tools:

more on microformats  0

Cat.: Talk, Python, microformats
04. September 2005

I’ve written previously on the trade-offs that microformats make in vocabulary design. I’m still not sure how I feel about the short-string issue, but it appears no one is waiting for me to make up my mind, so I figured I’d try it out.

So far I like it that microformats depend on well-understood technology, and that a lazy dev could point their HTML rendering component at the page if they didn’t feel like writing support. OTOH, parsing can be a bear. I think I may have cheated a little in that I insisted on XHTML, but even that had its own problems, since it’s tied to a DTD. Either you write your own entity resolver or the XML parser downloads three DTD files from w3.org. Rotten. I let my example client do just that in the interest of brevity.

On the lesscode side of things, the draft includes Python implementations of a client and server. With margins, the IETF txt format ends up allowing something less than the usual number of columns, so it cramped my Python style a little bit. I think they ended up pretty short, but one of the nice things about Python is that someone can always show you a way to do it that’s shorter and clearer. So, let’s have it! (no generators allowed, to keep things adaptable to those other languages :)

O’Reilly CodeZoo Language Requests  4

Cat.: Python, Ruby, Perl, PHP, Then you win.
04. August 2005

This chart showing the number of requests for different languages on O’Reilly’s Code Zoo is interesting:

CodeZoo language breakdown

Yesterday we added two new languages to CodeZoo: Python and Ruby. You can see from the language requests graph, above, the languages for which we got more than a few requests (I’ve left off Cobol and the others that only were requested a couple of times). From this, the choice of Python is completely obvious — it was the winner in the request race, beating out C++ and many other languages that might be considered “larger” by other metrics. In addition to the clear demand for it, Python is a natural fit for O’Reilly, since we publish a great deal of treeware and online material about Python, and cover Python extensively at our conferences (especially at the Open Source Convention taking place this week).

Ruby, however, is tied for fifth on the list, and in raw component counts on our site, it is the smallest of the languages we support. As we’ve discussed on Radar over the past few months, we see Ruby as an emerging force in the open source world, driven by interest in Ruby on Rails, and by the excellent books on Ruby written by the Pragmatic Programmers…

I was actually really surprised at how strongly dynamic languages showed up on this chart. I’m eye-balling it as there aren’t any numbers but Python, PHP, Ruby, and Perl seem to have taken down almost 50% of the requests with C{,#,++} taking down a large majority of the rest. Is this a fair sampling of the general development population? Developers with a web/UNIXy background seem to be over-represented at O’Reilly so its probably a bit skewed, no? Still, the amount of acceptance dynamic languages are gaining is pretty staggering at this point.