Three Reasons to Use FitNesse 2

Posted by Micah Fri, 19 Jan 2007 15:50:00 GMT

1. You find your self delivering software to your customer who says “That’s not what I asked for.”

Using FitNesse allows you to communicate with the customer up front. Before a line of code is written, you can have all the behavior expressed in an executable format. Make sure the customer helps to write these tests. Once your FitNesse test is in place, all you need to do it make it pass. Due to the cut-and-dry aspect of executable specifications (FitNesse test), one the spec is passing, you have delivered precisely what your customer asked for.

2. Bugs sneak into your system as development progresses and these bugs takes weeks to find and remove.

FitNesse is a tools to help you drive development with tests. When practices with discipline, test driven development will insure that you have a FitNesse test for each and every feature in your system. The moment a bug is introduced, you will know about it because a FitNesse test will fail.

3. It is difficult to create documentation for your system and it is constantly out of date because the system is changing.

FitNesse offers a unique documentation solution. When ever you write a FitNesse test, you are in fact describing how the system works. In other words you’re documenting it. The web/wiki based nature of FitNesse makes documentation simple and convenient. The best part is that the documentation in FitNesse can never go out of date. Since you’re keeping your test passing, and your tests are documentation, it’s impossible for them to lie.


There is an article I wrote about FitNesse for Windows Developer Power Tools. This book, just released today, includes articles on dozens of free tools that .NET developers might benefit from. If you write .NET code, check it out. If not, keep in mind that FitNesse will work for almost any language.

Getting started with Rails and FitNesse 1

Posted by Paul Pagel Mon, 15 Jan 2007 14:54:00 GMT

This is intended to be a tutorial to get you started using FitNesse with ruby on Rails. There is some explanation needed about FitNesse, Fit, and Rails. Smart people have written about such things, I will leave you to google them as interested. Two good references are listed at the bottom of this tutorial.

So lets get started. Our customer has just written a test that looks like this:
|vending machine|
|check|amount|$0.00|
|enter|currency|$.35|
|press|add change|
|check|amount|$.35|
|enter|selection|juicy fruit|
|press|vend|
|check|amount|$0.00|
This would be a common first fixture for a product, as it is limited in scope, it is a very specific example from which to build a conversation about requirements about. Anyway, the first thing to making this pass is getting some of the FitNesse infrastructure in place around your rails app.
First, lets create a rails app for our vending machine
$rails vending_machine

We see all the normal rails stuff, all the creates.
Lets download FitNesse and place it in our vending_machine root directory. FitNesse can be downloaded at http://fitnesse.org. And start the FitNesse server.
So, now we go to the FitNesse main page and create the page for our acceptance test. Then put the test from the customer into the page and try to run it. Failures? We need to set up the environment to run with ruby fit. Follow the instructions here (http://fitnesse.org/FitServers.RubyFit) to set up the right test runner for ruby.
Lets write our first fixture in a fixtures directory we create in the root folder.
Our new test with the path and test runner set up looks like this
!define COMMAND_PATTERN {ruby -I%p ruby/bin/FitServer.rb}
!path 

!3 Make one transaction with a vending machine
!|fixtures.VendingMachine| |check|amount|$0.00| |enter|currency|$.35| |press|add change| |check|amount|$.35| |enter|selection|juicy fruit| |press|vend| |check|amount|$0.00|
There are a few things to notice about the changes.
* The path is the rails root dir.
* Fixtures.VendingMachine is mapping to the folder name/module name of where the fixutures are located. In this instance it is a folder in the rails directory called fixtures.
* If you run the test, you will get all sorts of exceptions, because the fixture code is not written yet.
Note: If the table is not even showing up when you run the fixture go here.
Now it is time to write a fixture to make this test fail without any exceptions. In the fixtures directory, create a file called vending_machine.rb. The naming of your fixtures maps with the name of your file, which it will require. Lets make a stub file to make the test fail without exceptions.
require 'ruby/lib/fit_helper'
module Fixtures
  class VendingMachineFixture < Fit::ActionFixture
    attr_accessor :currency, :selection
    
    def initialize
      super
      @@actor = self
    end
    
    def add_change
    end
    
    def vend
    end
   
  end
end
Now we should have failures with the amount not changing.
Lets create our controller for the vending machine and start to implement the code. I am going to leave out the specs I use to write the controller, just show the code. Here is the first version of the controller. Note it has the same stubbed methods the fixture has.
class VendingMachineController < ApplicationController
  def add_change
  end
  def vend
  end
end

Lets hook up the fixture to the imaginary controller. There is a fair amount of set up which is rails related.
First, we need to load up the environment and the controllers. Add these lines to the beginning of your fixture.
require File.expand_path(File.dirname(__FILE__) + "/config/environment")
require File.expand_path(File.dirname(__FILE__) + '/app/controllers/application')

Which should allow us to change the initialize method to:
def initialize
      super
      @@actor = self
      @controller = VendingMachineController.new
      @controller.params = {}
    end

Which creates the controller, and initializes its params to an empty dictionary. There are other ways to do this, like creating test params, but for simplicity, we are going to create our own for now.
Next, we set up the values in the params and call the controller methods.
    def add_change
      @controller.params[:amount] = @currency
      @controller.add_change  
    end
    
    def vend
      @controller.params[:selection] = @selection
      @controller.vend
    end

Now, we make the test pass by implementing the controller.
class VendingMachineController < ApplicationController
  
  def initialize
    @items = {"juicy fruit" => 35 , "doublemint" => 45 }
    @session = {} if not @session
    @session[:amount_entered] = 0.0;
  end
  
  def add_change
    @session[:amount_entered] += params[:amount].to_f
  end
  
  def vend
    @items.each_pair do |key, value|
      if(params[:selection] == key)
        @session[:amount_entered] = 0.0
      end
    end
  end
end

Missing Requires

There is some weirdness around the way RubyFit collects exceptions after failing to find the file to require. If this occurs, dig into ruby fit’s FixtureLoader, specifically the find_class method. Usually you can get some information from the exceptions being silently caught.

References

http://fit.rubyforge.org/basics.html - RubyFit http://www.cornetdesign.com/2005/12/fitnesse-and-ruby-basic-tutorial.html - Fitnesse and Ruby

Understanding Statemachines, Part 2: Actions 3

Posted by Micah Thu, 30 Nov 2006 04:20:00 GMT

Actions

Part 1 demonstrated how to build states and transitions. Add some actions to that and you’ve got a truly useful statemachine. Actions allow statemachines to perform operations at various point during execution. There are two models for incorporating actions into statemachines.

Mealy: A Mealy machine performs actions on transitions. Each transition in a statemachine may invoke a unique action.

Moore: A Moore machine performs actions when entering a state. Each state may have it’s own entry action.

Mealy and Moore machines each have advantages and disadvantages. But one great advantage of both it that they are not mutually exclusive. If we use both models, and toss in some exit actions, we’ve got it made!

Example:

Remember the vending machine statemachine. It had some problems. Adding some actions will solve many of them. Here’s the same statemachine with actions.


The Vending Machine Statemachine Diagram, Version 2

You can see I’ve added three transition actions (the Mealy type). Check out the transition from Waiting to Paid. When this transition is triggered the activate action will be called which will activate the hardware that dispenses goodies. Also, when a selection is made, transitioning from Paid to Waiting, the release action will cause the hardware to release the selected product. Finally, this version of the vending machine won’t steal your money any more. When an extra dollar is inserted, the refund event is invoked and the dollar is refunded.

Notice that the Waiting state has an entry action (Moore type) and an exit action. When ever the Waiting states is entered, the sales_mode action is invoked. The intent of this action is to make the vending machine blink or flash or scroll text; whatever it takes to attract customers. When the Waiting state is exited, the vending will go into operation_mode where all the blinking stops so the customer do business.

Implementation:

Here’s how the new vending machine can be implemented in Ruby:

vending_machine = Statemachine.build do
  state :waiting do
    event :dollar, :paid, :activate
    event :selection, :waiting
    on_entry :sales_mode
    on_exit :operation_mode
  end
  trans :paid, :selection, :waiting, :release
  trans :paid, :dollar, :paid, :refund
  context VendingMachineContext.new
end

There are several new tricks to learn here. First is the state method. This is the formal syntax for declaring a state. The informal syntax is the trans method which we’ve already seen. The state method requires the state id and an option block. Every method invoked within the block is applied to the state being declared.

With a state block you may declare events, entry actions, and exit actions. The event method is used to declare transition out of the current state. Its parameters are the event, destination state, and an optional action. The on_entry and on_exit methods are straight forward. They take one parameter: an action. (See below for more on action syntax)

After the waiting state declaration we see the familiar calls to trans. The trans method takes an option 4th action parameter. You can see that the release and refund actions were added this way.

Context:

The final line sets the context of the statemachine. This is an interesting aspect. Every statemachine may have a context and if your statemachine has actions, you should definitely give it a context. Every action of a statemachine will be executed within its context object. We’ll discuss this more later.

Here is a simple context for the vending machine statemachine.

class VendingMachineContext

  def activate
    puts "activating"
  end

  def release(product)
    puts "releasing product: #{product}"
  end

  def refund
    puts "refuding dollar"
  end

  def sales_mode
    puts "going into sales mode"
  end

  def operation_mode
    puts "going into operation mode"
  end

end

Action Declarations:

With the statemachine gem, actions can be declared in any of three forms: Symbols, String, or Block.

When the action is a Symbol, (on_entry :sales_mode) it is assumes that there is a method by the same name on the context class. This method will be invoked. Any parameters in with the event will be passed along to the invoked method.

String actions should contains ruby code (on_entry "puts 'entering sales mode'"). The string will use invoked with in the context object using instance_eval. Strings allow quick and dirty actions without the overhead of defining methods on your context class. The disadvantage of String actions is that they cannot accept parameters.

If the action is a Proc (on_entry Proc.new {puts 'entering sales mode'}), it will be called within the context of the context. Proc actions are also nice for quick and dirty actions. They can accept parameters and are preferred to String actions, unless you want to marshal your statemachine. Using one Proc actions will prevent the entire statemachine from being marhsal-able.

Execution

For kicks let’s put this statemachine thought a few events.

vending_machine.dollar
vending_machine.dollar
vending_machine.selection "Peanuts"

Here’s the output:

going into operation mode
activating
refuding dollar
releasing product: Peanuts
going into sales mode

That sums it up for actions. Next, we’ll talk about how do deal with conditional login in your statemachine.

Understanding Statemachines, Part 3: Conditional Logic

Older posts: 1 ... 19 20 21 22 23 ... 29