Using Storyteller against Jasper Systems Edit on GitHub


Jasper comes with a pre-built recipe for doing integration or acceptance testing with Storyteller using the Jasper.Storyteller extension library.

To get started with this package, create a new console application in your solution and add the Jasper.Storyteller Nuget dependency. Next, in the Program.Main() method, use this code to connect your application to Storyteller:


JasperStorytellerHost.Run<MyJasperAppRegistry>(args);

In this case, MyJasperAppRegistry would be the name of whatever the JasperRegistry class is for your application.

If you want to hook into events during the Storyteller bootstrapping, teardown, or specification execution, you can subclass JasperStorytellerHost<T> like this:


public class MyJasperStorytellerHarness : JasperStorytellerHost<MyJasperAppRegistry>
{
    public MyJasperStorytellerHarness()
    {

        // Customize the application by adding testing concerns,
        // extra logging, or maybe override service registrations
        // with stubs
        Registry.Hosting.UseEnvironment("Testing");
    }

    protected override void beforeAll()
    {
        // Runs before any specification are executed one time
        // Perfect place to load any kind of static data

        // Note that you have access to the JasperRuntime
        // of the running application here
        Runtime.Get<ISomeService>().StartUp();
    }

    protected override void afterEach(ISpecContext context)
    {
        // Called immediately after each specification is executed
        Runtime.Get<ISomeService>().CleanUpTestRunData();
    }

    protected override void beforeEach()
    {
        // Called immediately before each specification is executed
        Runtime.Get<ISomeService>().LoadTestingData();
    }

    protected override void afterAll()
    {
        // Called right before shutting down the Storyteller harness
        Runtime.Get<ISomeService>().Shutdown();
    }
}

Then, your bootstrapping changes slightly to:


StorytellerAgent.Run(args, new MyJasperStorytellerHarness());

MessagingFixture

Jasper.Storyteller also comes with a MessagingFixture base class you can use to create Storyteller Fixtures that send messages to the running service bus with some facility to use the built in Message Tracking to "know" when all the activity related to the message being sent has completed.

Here's a sample MessagingFixture from the sample project:


public class TeamFixture : MessagingFixture
{
    [FormatAs("A new team {team} has joined the league")]
    public Task CreateNewTeam(string team)
    {
        // This method sends a message to the service bus and waits
        // until it can detect that the message has been fully processed
        // on the receiving side or timed out
        return SendMessageAndWaitForCompletion(new TeamAdded {Name = team});
    }

    [FormatAs("On {day}, the score was {homeTeam} {homeScore} vs. {visitorTeam} {visitorScore}")]
    public Task RecordGameResult(DateTime day, string homeTeam, int homeScore, string visitorTeam, int visitorScore)
    {
        var message = new GamePlayed
        {
            Date = day.Date,
            Home = new TeamResult{Name = homeTeam, Score = homeScore},
            Visitor = new TeamResult{Name = visitorTeam, Score = visitorScore}
        };

        return SendMessageAndWaitForCompletion(message);
    }

    [FormatAs("Send an un-handled message")]
    public Task SendUnHandledMessage()
    {
        return SendMessageAndWaitForCompletion(new UnhandledMessage());
    }
}

Diagnostics

If there is any messages sent or received by the service bus feature during a Storyteller specification, there will be a custom results tab called "Messages" in the Storyteller specification results that presents information about the message activity that will look like this:

content/storyteller-messaging-log.png

External Nodes

Note! This isn't super duper mature yet. We had a similar feature in FubuMVC that we'd like to have back, so look for more here later.

It's not for the feint of heart, but it's also possible to write automated tests using Storyteller against additional systems for true integration testing.

To bootstrap an additional Jasper application in the same Storyteller host, use the "external nodes" feature like this:


var host = new JasperStorytellerHost<MyJasperAppRegistry>();
host.AddNode(new OtherApp());

return StorytellerAgent.Run(args, host);

If you're using MessagingFixture, you'll have access to the external nodes as shown in this fixture:


public class IncrementFixture : MessagingFixture
{

    [FormatAs("Send increment message from the other application")]
    public Task SendIncrementMessage()
    {
        // Just to show the functionality, you can get at the JasperRuntime
        // -- and therefore everything about the other app -- by
        // using the NodeFor() method as shown below:
        var node = NodeFor("other");
        var otherRuntime = node.Runtime;


        // This sends a message from the external node named "Other"
        return SendMessageAndWaitForCompletion("Other", new Increment());
    }

    [FormatAs("The current count should be {count}")]
    public int TheIncrementCountShouldBe()
    {
        var counter = Context.Service<IncrementCounter>();
        return counter.Count;
    }
}