Exploration Through Example

Example-driven development, Agile testing, context-driven testing, Agile programming, Ruby, and other things of interest to Brian Marick
191.8 167.2 186.2 183.6 184.0 183.2 184.6

Wed, 21 Sep 2005

A tour through a Fit episode

On the agile-testing list, someone asked this question:

What I mean is a workflow requirement like:

If A then
  do something (which may be an entire function in itself)
Else if B
  then do something else
Else if C
  Then do nothing

Is it possible to express a requirement of this sort using Fit/Fitnesse?

Here's my answer, which goes afield into business-facing test-driven design.

My inclination would be to test the business rule directly. Here, I'm using Rick Mugridge's CalculateFixture. With it, the inputs and expected results are separated by a blank column.

All Significant Events in the Reactor's Life
condition   operator notified? auto shutdown?
really hot   YES YES
slightly hot   YES no
temp goes in range   no no

(An alternative would be to have a single column named reaction?. Each cell would contain a list of all relevant reactions for a condition. My problem with that is it's too easy to overlook a reaction if you're just going down a reaction column and filling in what comes to mind. Enumerating the possibilities in columns forces you to come up with an exhaustive list of all noteworthy reactions and also think about each reaction for each condition.)

What are we really testing here? Assuming that the reactor is event-driven-ish, it's that the reactor has the right reaction to a particular event. Were the fixture written in Ruby, it would have two methods like this:


  def operator_notified_question_condition(condition)
    # create an event for the condition.
    # Send the event into the system.
    # check whether the operator has been notified.
  end

The name of the method indicates that it's the one called to check operator notified? after the reactor code processes condition. CalculateFixture, unlike ColumnFixture, doesn't stuff values into fields (which isn't something that bothers me, though it does bother some people).

We have to decide what the system under test does and what the fixture does. (A truly hardcore TDD person would put everything in the fixture until there was some reason to move it into the product; I'll skip that.) I'm going to assume the system under test is in the variable @model, and flesh out the above this way:


  def operator_notified_question_condition(condition)
    event = create_event_for(condition)
    @model.accept_event(event)
    was_operator_notified?
  end

  def create_event_for(condition)
    # how to create the event?
  end

  def was_operator_notified?
    # how to check that?
  end
  

The two questions in that code raise questions for the team. Consider the second. It's the product expert we go to when we want to know what form operator notification should take. (Hoping all the while that she knows more about human factors than we do.)

  • Her response might be that such and so a light should flash and such and so a message should appear on such and so a screen. In that case, the code could check whether the right messages are sent to the right hardware interfaces (or mocked-out versions of them).

  • But I'd be tempted to ask the product owner about the log at this point. A reactor presumably has some sort of logging (perhaps some form of "black box"). Each test column names a significant reaction. Should each be logged? If so, we can just check the log:

      def operator_notified_of?(event)
        notification = model.log.most_recent_entry(:type => :operator_notification)
        return "yes" if notification.timestamp.later_than?(event.timestamp)
        "no"  # returns "no" unless previous line returned "yes".
      end

What the second choice lets us do is defer the decision about the details of operator notification until later tests. All I need to know now is that it at least makes a log entry. Never decide today what you can put off til tomorrow.

So I could write accept_event like this:


  def accept_event(event)
    case event.class
    when ReallyHotTemperatureEvent:
       log(...)
    end
  end

So what this test is forcing me (as the programmer) to do is lay down the first bits of event-handling code and possibly the first bits of logging code (which would be a matter of starting to use Log4R or some other logger). Similarly, writing create_event_for is going to mean a little translation of strings and then calls into (as yet nonexistent) event creation code.

So this single high-level test only produces some high-level structural code. Each of the inexact terms - really hot, auto shutdown - will later be examplified (sic) with tests. I find this sort of top-down test-driven approach comfortable to work with. For me, it does seem to result in a lot of backtracking to remake bad decisions about structure. It seems I ought to be able to do better, but that's the way I feel about pretty much everything I do.

## Posted at 12:48 in category /agile [permalink] [top]

Ruby makes the big time

My son is going to a birthday party this weekend. He wanted to get the birthday boy (Jody) two plush toy giant microbes. He chose Ebola and flesh-eating bacteria. (Yes, this was after I made several attempts to get him to choose something less gruesome, like the common cold or ulcer, because I didn't want his mother to think "what kind of bizarre child does my Jody hang around with?" But Paul insisted that Jody really likes that kind of thing. (What kind of bizarre child does my Paul hang around with?)

In any case, he prevailed, and I purchased the two toys at ThinkGeek. Along the way, I took their 46.4 second feedback survey. It asks what your favorite language is. I scanned down to the Rs and was appalled to find that Ruby wasn't listed, though Rebol and Rexx were and Python was just above them. But I later noticed that the list is not entirely alphabetical. Certain languages have been promoted to the front of the list: C, C++, Objective C, Perl, Java, ..., and Ruby. This is the big time, folks.

P.S. If you're from ThinkGeek: sorry about the rant in your Suggestions / Comments / Thoughts / Rants text area. That was before I noticed Ruby at the top.

## Posted at 09:25 in category /ruby [permalink] [top]

About Brian Marick
I consult mainly on Agile software development, with a special focus on how testing fits in.

Contact me here: marick@exampler.com.

 

Syndication

 

Agile Testing Directions
Introduction
Tests and examples
Technology-facing programmer support
Business-facing team support
Business-facing product critiques
Technology-facing product critiques
Testers on agile projects
Postscript

Permalink to this list

 

Working your way out of the automated GUI testing tarpit
  1. Three ways of writing the same test
  2. A test should deduce its setup path
  3. Convert the suite one failure at a time
  4. You should be able to get to any page in one step
  5. Extract fast tests about single pages
  6. Link checking without clicking on links
  7. Workflow tests remain GUI tests
Permalink to this list

 

Design-Driven Test-Driven Design
Creating a test
Making it (barely) run
Views and presenters appear
Hooking up the real GUI

 

Popular Articles
A roadmap for testing on an agile project: When consulting on testing in Agile projects, I like to call this plan "what I'm biased toward."

Tacit knowledge: Experts often have no theory of their work. They simply perform skillfully.

Process and personality: Every article on methodology implicitly begins "Let's talk about me."

 

Related Weblogs

Wayne Allen
James Bach
Laurent Bossavit
William Caputo
Mike Clark
Rachel Davies
Esther Derby
Michael Feathers
Developer Testing
Chad Fowler
Martin Fowler
Alan Francis
Elisabeth Hendrickson
Grig Gheorghiu
Andy Hunt
Ben Hyde
Ron Jeffries
Jonathan Kohl
Dave Liebreich
Jeff Patton
Bret Pettichord
Hiring Johanna Rothman
Managing Johanna Rothman
Kevin Rutherford
Christian Sepulveda
James Shore
Jeff Sutherland
Pragmatic Dave Thomas
Glenn Vanderburg
Greg Vaughn
Eugene Wallingford
Jim Weirich

 

Where to Find Me


Software Practice Advancement

 

Archives
All of 2006
All of 2005
All of 2004
All of 2003

 

Join!

Agile Alliance Logo