Sponsored By Aspose - File Format APIs for .NET

Aspose are the market leader of .NET APIs for file business formats – natively work with DOCX, XLSX, PPT, PDF, MSG, MPP, images formats and many more!

StoryTeller Beta 0.7 Is Here! Come and get it!

I owe some folks a couple blog posts, but I had to get this puppy out of the way.  This white whale is swimming free, but I’ve got StoryTeller in my harpoon sights.

I announced StoryTeller nearly a year ago and its finally getting close to a real release.  The tagline is simply this:  “StoryTeller is the FitNesse killer for .Net.”  My express goal is to fulfil the promise of FitNesse with less frustration and friction.  This isn’t really about criticism of FitNesse so much as just trying to make the next step.  This tool would not exist without the inspiration or FitNesse.

I have absolutely zero intention at this moment at making StoryTeller run Fit tests in anything other than .Net.  StoryTeller is intended to provide the best possible experience for .Net development without compromising for cross language support.  Besides, there are other tools for Java and other languages.

From the original announcement:

StoryTeller is a new tool for efficient creation and management of automated testing of .Net code with the NFit/FitNesse engine.  StoryTeller is specifically created to support an Acceptance Test Driven Development strategy.  All existing .Net FitNesse tests will run under StoryTeller.  Features will include editing, tagging, and integration with source control, CruiseControl.Net, NAnt and/or MSBuild, and support for application versioning.



It’s taken a long time, and it’s not really done yet, but I finally feel like I’ve got enough here to warrant a real release.  The UI client is still rough, but it does work.  I’m thrilled with the response to a call for beta testers, so here it is:

StoryTeller Beta 0.7



And I did the amateurish thing by creating the package by copying all the files in bin/debug which inevitably misses GAC’ed assemblies.  So also go download the telerik assemblies at http://storyteller.tigris.org/svn/storyteller/trunk/tools/telerik.

I’ll get the zip repackaged tonight.

Download the zip file, unzip, and double click on the executable and you should be good to go.


Things to Know

  • StoryTeller is aimed very squarely as a replacement for FitNesse on .Net projects.  It still uses the same test engine.
  • StoryTeller stores the test files as either HTML or Wiki text.  Some options aren’t supported with the Wiki text.  One of my goals was to make the tests easy to edit by hand or your html tool of choice.
  • You edit the tests inside the StoryTeller GUI with a subset of the FitNesse Wiki format.  See the FitNesse website for more details.
  • SetUp & TearDown works a little differently than FitNesse.  You can optionally define a SetUp and/or TearDown for any Suite.  When a test executes, StoryTeller will execute the SetUp, if one is found, for each anscestor Suite.  For example, a test with the path “Suite1.Suite2.Suite3.Test1″ will first run “Suite1.SetUp” then “Suite1.Suite2.SetUp” then “Suite1.Suite2.Suite3.SetUp” before executing the actual test.  TearDown’s work similarly, but in reverse order.  The TearDown’s are executed by the inner most parent in this order:  “GrandParent.Parent.TearDown” then “GrandParent.TearDown” and so on.


Starting a New Project

The first thing to do is to configure a new StoryTeller project.  Inevitably, it’s an Xml file.  There is a form in the client to configure the Xml file, but for the sake of documentation I’m going to describe the Xml file (it’s just a serialized object by the way).  The sample project file looks like this:


<?xml version="1.0"?>
<Project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <!-- List of all possible tags for the project-->
       The only valid Project type is "Local" for the moment.  I had a "FitNesse" project at one time and plans for a "Remote" project.
       All it means is that the tests are run locally
    The directory containing the assemblies and configuration files for the SystemUnderTest.  The StoryTeller.dll must also be in this folder 
    The path can be either absolute or relative to the project file  
    Optional, but recommended.  As assembly qualified name of a class that implements the StoryTeller.IFixtureLibrary interface.
    The role of the IFixtureLibrary interface is simply to register Fixture type's with the Fit engine.    
    The folder that contains the StoryTeller tests.  The root Suite's will each be a directory under this folder.  
    The path can be either absolute or relative to the project file  
  <!-- The displayed name of the SystemUnderTest -->
  <Name>Test Application</Name>
  <!-- Controls the format that the StoryTeller engine uses to persist tests.  At this time I *strongly* suggest the HTML option-->
  <!-- Set a timeout on test execution.  Any number <= 0 will be treated as infinity.  The TimeOut is somewhat problematic at the moment-->
    Purely desperation.  If you need a completely clean AppDomain for each and every test run, choose this option.
    Needless to say, this will slow down the execution time to a painful crawl.  And yes, I had to have this in a previous


Running from the Command Line

There is a command line runner called StoryTellerRunner.exe in the download for running StoryTeller tests from a command line.  This is the tool for integration with build scripts.  I originally intended to do this with NAnt tasks, but decided on the command line approach for maximum reach.  The command line is:

StoryTellerRunner.exe ProjectFile OutputFile \n [-description:AAA]\n [-suite:AAA]\n [-tag:value] (can be repeated)

  • ProjectFile is the path to the StoryTeller project file
  • OutputFile is where you want the TestReport to be saved
  • -description:Text is simply a way to add a description to the TestReport
  • -suite:Suite Path is the path to the Suite you want to run.  Use this to limit the test run to only this Suite
  • -tag:value – run tests with this tag
  • -status:Acceptance or -status:Regression – Only run tests in this state.  Conceptually, you could make one test run that executes all the Acceptance tests but doesn’t fail the build, and a second regression test run that will fail the build on any test failures.


What’s Left

It’s not complete, and I’m hoping to do one more beta before 1.0.  I’m releasing this now to get feedback.  From the response I’ve gotten, there’s an obvious demand for something like StoryTeller.  The stuff that I’ve definitely got left is:

  • Syntax checking – Simply highlight test rows that don’t match up with the Fixture classes
  • A Fixture explorer in the UI tool
  • Exporting reports and results from the client
  • Reloading a project
  • Canceling tests in the execution queue
  • Creating playlists on the flow
  • Adding the component versions to the test reports
  • Making the UI not be butt ugly
  • Docs, lots of docs

About Jeremy Miller

Jeremy is the Chief Software Architect at Dovetail Software, the coolest ISV in Austin. Jeremy began his IT career writing "Shadow IT" applications to automate his engineering documentation, then wandered into software development because it looked like more fun. Jeremy is the author of the open source StructureMap tool for Dependency Injection with .Net, StoryTeller for supercharged acceptance testing in .Net, and one of the principal developers behind FubuMVC. Jeremy's thoughts on all things software can be found at The Shade Tree Developer at http://codebetter.com/jeremymiller.
This entry was posted in StoryTeller. Bookmark the permalink. Follow any comments here with the RSS feed for this post.
  • http://www.bgeek.net Owen Evans

    Ok I’ve brought up the Add Suite dialogue, but I can’t get the OK button to enable, I think I might have found a defect. I’ve tried both the add suite button, and the right click menu.

    eventually I got the ok button to enable (by hitting ctr-enter) but then get an error:
    See the end of this message for details on invoking
    just-in-time (JIT) debugging instead of this dialog box.

    ************** Exception Text **************
    StructureMap.StructureMapException: StructureMap Exception Code: 207
    Internal exception in the constructor function of the targeted concrete type. InstanceKey “StoryTeller.UserInterface.Suites.SuiteView,StoryTeller.UserInterface”, PluginFamily StoryTeller.UserInterface.Suites.ISuiteView —> System.ApplicationException: Unable to bind property Status —> System.Reflection.TargetException: Non-static method requires a target.
    at System.Reflection.RuntimeMethodInfo.CheckConsistency(Object target)
    at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture, Boolean skipVisibilityChecks)
    at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
    at System.Reflection.RuntimePropertyInfo.GetValue(Object obj, BindingFlags invokeAttr, Binder binder, Object[] index, CultureInfo culture)
    at System.Reflection.RuntimePropertyInfo.GetValue(Object obj, Object[] index)
    at StoryTeller.DataBinding.Elements.ScreenElement`2.Bind(Object target) in d:\StoryTeller\src\StoryTeller.DataBinding\Elements\ScreenElement.cs:line 196
    — End of inner exception stack trace —
    at StoryTeller.DataBinding.Elements.ScreenElement`2.Bind(Object target) in d:\StoryTeller\src\StoryTeller.DataBinding\Elements\ScreenElement.cs:line 202
    at StoryTeller.DataBinding.ScreenBinder`1.<>c__DisplayClasse.b__d() in d:\StoryTeller\src\StoryTeller.DataBinding\ScreenBinder.cs:line 293
    at StoryTeller.DataBinding.ScreenBinder`1.withinLatch(VoidHandler handler) in d:\StoryTeller\src\StoryTeller.DataBinding\ScreenBinder.cs:line 282
    at StoryTeller.DataBinding.ScreenBinder`1.BindScreenTo(T target) in d:\StoryTeller\src\StoryTeller.DataBinding\ScreenBinder.cs:line 289
    at StoryTeller.UserInterface.TestEditing.TestHeaderControl.set_TaggedLeaf(TaggedLeaf value) in d:\StoryTeller\src\StoryTeller.UserInterface\TestEditing\TestHeaderControl.cs:line 59
    at StoryTeller.UserInterface.Suites.SuiteView.InitializeComponent() in d:\StoryTeller\src\StoryTeller.UserInterface\Suites\SuiteView.Designer.cs:line 42
    at StoryTeller.UserInterface.Suites.SuiteView..ctor() in d:\StoryTeller\src\StoryTeller.UserInterface\Suites\SuiteView.cs:line 10
    at StoryTellerUserInterfaceSuitesSuiteViewInstanceBuilder.BuildInstance(InstanceMemento )
    at StructureMap.InstanceFactory.BuildInstance(InstanceMemento memento)
    — End of inner exception stack trace —
    at StructureMap.InstanceFactory.BuildInstance(InstanceMemento memento)
    at StructureMap.InstanceMemento.Build(IInstanceCreator creator)
    at StructureMap.InstanceFactory.GetInstance()
    at StructureMap.InstanceMemento.buildDefaultChild(String key, InstanceManager manager, String typeName)
    at StructureMap.InstanceMemento.GetChild(String key, String typeName, InstanceManager manager)
    at StoryTellerUserInterfaceSuitesSuitePresenterInstanceBuilder.BuildInstance(InstanceMemento )
    at StructureMap.InstanceFactory.BuildInstance(InstanceMemento memento)
    at StructureMap.InstanceMemento.Build(IInstanceCreator creator)
    at StructureMap.InstanceFactory.GetInstance()
    at StructureMap.InstanceManager.CreateInstance(Type pluginType)
    at StructureMap.ObjectFactory.GetInstance[TargetType]()
    at StoryTeller.UserInterface.Commands.Suites.AddSuiteCommand.createLeafPresenterPair(ISuiteHolder suite) in d:\StoryTeller\src\StoryTeller.UserInterface\Commands\Suites\AddSuiteCommand.cs:line 38
    at StoryTeller.UserInterface.Commands.AddLeafCommand.Execute() in d:\StoryTeller\src\StoryTeller.UserInterface\Commands\Fragments\AddLeafCommand.cs:line 70
    at StoryTeller.UserInterface.Dialogs.CommandDialog.okButton_Click(Object sender, EventArgs e) in d:\StoryTeller\src\StoryTeller.UserInterface\Dialogs\CommandDialog.cs:line 72
    at System.Windows.Forms.Control.OnClick(EventArgs e)
    at System.Windows.Forms.Button.OnClick(EventArgs e)
    at System.Windows.Forms.Button.PerformClick()
    at System.Windows.Forms.Form.ProcessDialogKey(Keys keyData)
    at System.Windows.Forms.Control.ProcessDialogKey(Keys keyData)
    at System.Windows.Forms.ContainerControl.ProcessDialogKey(Keys keyData)
    at System.Windows.Forms.Control.ProcessDialogKey(Keys keyData)
    at System.Windows.Forms.TextBoxBase.ProcessDialogKey(Keys keyData)
    at System.Windows.Forms.Control.PreProcessMessage(Message& msg)
    at System.Windows.Forms.Control.PreProcessControlMessageInternal(Control target, Message& msg)
    at System.Windows.Forms.Application.ThreadContext.PreTranslateMessage(MSG& msg)


  • http://weblogs.asp.net/bsimser Bil Simser


    I sit down next week and put togeher a few screen casts for setting things up for this puppy. I’ve been working with Fitnesse for a couple of years now and with this since you started and even I had problems getting everything going. I’ll also get in and fix your butt ugly UI, even some dialogs were cut off so I couldn’t even tell what they wanted.

    PS the website cuts off and is a little crappy under Firefox. I know, it’s CS and not your problem, I’m just in a ranting mood today.

  • http://codebetter.com/blogs/jeremy.miller Jeremy D. Miller


    Ugh. Right now StoryTeller only runs locally, which is a *huge* advantage over FitNesse for developers, but doesn’t help testers out all that much. One of my plans was to create a windows service that would run the StoryTeller engine on the server. The StoryTeller client would have a mode that allowed you to run the tests against the deployed engine on the server. I’ll pose this question on the StoryTeller list and see who else wants it.

    And no, you won’t be able to run this through FitNesse. This is meant as a complete replacement of the FitNesse Wiki.

    @Bill, Documentation is on the way within a month for the real 1.0 release. Right now it probably is confusing for anyone without FitNesse experience and I’ll have to do something about that.

    @Owen, The screencast is probably a great idea. For right now, add a suite(s) to the project, then add tests to the suites. Either select the project node in the UI or right click the project node to get the option for “Add Suite.” Then do the same thing on a Suite node to “Add Test”. All tests have to belong to a Suite.

  • http://www.bgeek.net Owen Evans

    Well i’ve got StoryTeller up and set the project up, but I can’t work out how on earth to add tests to the project.
    Could you maybe put together a quick tutorial or screen cast on getting started?

  • Bill Campbell

    Wow! This sounds excellent! So, if one’s never used Fitnesse, how would one get started with using this? Or is this something that your coming documentation will cover?


  • Morten

    Great stuff, Jeremy! :-)

    I have one question: One of the things my non-techs like is that they can open Fitnesse and run a suite to get a great indication on the progress of a certain feature or set of features. Will I be able to still run my tests from within FitNesse?


  • http://codebetter.com/blogs/jeremy.miller Jeremy D. Miller

    I’ve updated the zip to include the telerik controls now.

  • http://www.scottlilly.com Scott Lilly

    If you create a Tigris account at http://www.tigris.org/servlets/Join, you can get access to the controls page.

  • http://hakanforss.spaces.live.com Håkan Forss

    The Telerik controls are password protected.