In preparing to teach a new class, Ruby on Rails Fundamentals, I felt strongly that I wanted to teach test-driven development (TDD).  Initially my motivation was that I found it hard to learn TDD when I learned Rails.  I found little instructional material on the web and the variety of test frameworks was a bit overwhelming.  As an experienced programmer, I understood the methodology (although I hadn’t practiced it much), but couldn’t find good resources to teach myself the basic syntax.  I found cucumber quite approachable, but struggled with TestUnit and RSpec (which I eventually learned well through pair programming).  I figured that if people didn’t learn TDD in an introductory class, how the heck were they to learn it at all?  Also, the last thing I want is for graduates of my class to have experience building web applications in Ruby on Rails that have no tests.

There were negative reactions from some folks via email and twitter, but I had just as many people encouraging the teaching of TDD, so I decided to move forward with my plan.  Wolfram Arnold is a big proponent of throwing the newbies into the status quo.  We should teach them the real thing, not yesterday’s news, and certainly not teach them practices that we would frown upon.  I reflected on my own TDD experience and realized that one of the benefits of TDD and one of the things that makes it hard is that I really need to understand what my code is doing to test it.  That might sound strange, but it is surprisingly easy to get an intended high-level effect you want without really understanding exactly what your code is doing, especially with Rails.  If you force yourself to write a test, you are creating a detailed contract with yourself.  It is a crystallization of your design that requires an understanding of the code.  I thought that would be really good for the class.  We could write tests that cover some important details that it is easy to gloss over as a newbie.  In this way, TDD would start as a teaching/learning tool, rather than the design tool that it usually is in a typical development process.

Today I met with another TDD teaching proponent, Alex Chafee.  He had twittered that he always teaches testing first, and I was intrigued. I joined his regular Sunday study group as a TA, where I had fun teaching about nested routes, debugging collection_select, and spreading the word about nested attributes.  After the class, a few students stayed late and joined me as I learned from Alex about his approach to teaching, which he calls test-driven teaching (TDT).  He did this intially in teaching java and more recently teaching Ruby.  For homework assignments he would give student tests and then they would write the code to make them pass.  This is one of those ideas that I hadn’t thought of, but as soon as he told me about it, the idea seemed an obvious way to teach.  What beter way to specify an assignment that to provide a test?

What I’d ike to do for the class is to start with TDT and then shift to TDD once the students are familiar enough with the Ruby syntax and the Rails object model.  It is perhaps aggressive for 6 2-hour classes, but with homework assignments between classes and students who are already programmers, it seems like it could fit into the time frame.

My first challenge is to figure out what are the essential Ruby language constructs that people need to know for writing Rails applications, what would be good exercises for learning those skills, and then write the tests that would require that code to be written.  It feels like a little bit ‘o Ruby jeopardy.  Alex has promised to meet with me again to brainstorm and I’ll publish what we come up with, but if you are reading this and you write Rails applications, I would love your feedback on what are the essential Ruby skills for a Rails engineer (plus any Ruby, Rails or TDD teaching tips would be welcome).

9 thoughts on “test-driven teaching

  1. Pingback: Revenge of the Link Roundup (August 17th, 2009) | Geek Feminism Blog

  2. Matt Aimonetti and I taught a course on Merb in Phoenix earlier this year (January) using tests for teaching. We would introduce each new section with some tests, and ask the students to try to make them pass. It was extremely successful, because the students weren’t just trying our some hypothetical new technique, they had red/green to determine whether they were successful.

  3. The Ruby Koans are awesome. I went through the first two and plan to set aside some time to meditate on them every day. It does seem like such exercises would benefit from guidance from a Ruby Master. For example, in the following two koans:

      # To understand reality, we must compare our expectations against
      # reality.
      def test_assert_equality
        expected_value = 2
        actual_value = 1 + 1
    
        assert expected_value == actual_value
      end
    
      # Some ways of asserting equality are better than others.
      def test_a_better_way_of_asserting_equality
        expected_value = 2
        actual_value = 1 + 1
    
        assert_equal expected_value, actual_value
    end
    

    Why is it that assert_equal expected, actual is better than assert expected == actual? It seems that the latter is quite legible and arguably more readable.

  4. IMO it’s because of the output you get when the assertion fails.

    a = 1
    b = 2
    assert a == b # failure message says ‘expected true but was false’
    assert_equal a, b # failure message says ‘expected 1 but was 2’

    The second failure message is more informative.

  5. Pingback: ruby unit test frameworks | the evolving ultrasaurus

  6. Pingback: learning through testing | the evolving ultrasaurus

  7. Pingback: Test-Driven Teaching! « Find Time for the Karussell

What do you think?