Using TripleA with BDD Frameworks

StoryQ and other BDD style frameworks provide their own constructs for creating a "sequence" of steps to execute to arrange, act and assert; for example StoryQ provides the Given/When/Then semantics so the TripleA pipeline is not required - we still want to use all the extensions but they need to be orchestrated by the BDD framework not TripleA.

StoryQ

StoryQ provides the Given/When/Then syntax to execute action delegates in sequence....TripleA provides extensions to arrange and assert system level components - a perfect match! The beauty of StoryQ is that the language to describe the test steps is completely divorced from the implementation so you can easily retrofit TripleA into your existing StoryQ tests.

Typical StoryQ test within an NUnit test class...(pseudo code)

[TestFixture]
public class Version123DeploymentTests
{
    [Test]
    public void NewUserRoleDeployed()
    {
         var story = new Story("deploying the new database role 'report_reader'")
              // skip boring story/scenario setup here
              .Given(ThatRelease_HasBeenDeployed, "1.2.3")
              .When(TheDatabaseIsCheckedForTheRole_, "report_reader")
                 .And(TheUser_IsInRole_, "svc_ReportingService", "report_reader")
              .Then(?????);
         story.ExecuteWithReport();
    }

    private void ThatRelease_HasBeenDeployed(string version)
    {
        // assert that this release has been applied
    }

    // other delegates...
}
Inside each delegate you might want to run a TripleA extension as part of that delegates operation. I use a "test domain" object to encapsulate my test implementation and create a new one for each test to ensure isolation of state (excluding external resources) is removed as a variable from the test. Another benefit of using a test domain it promotes a clear separation between the specifications and the test implementation (the domain). I usually put the specs in a FeatureSpecs.cs file and the domain in a FeatureDomain.cs file.

This is how I use StoryQ...

  1. Install the TripleA.StoryQ NuGet package into your test project.
    1. This will automatically install the TripleA and StoryQ NuGet packages for you.
  2. Make your test class inherit from TripleA.StoryQ.BddFeature
    1. This will force you to implement the "DescribeFeature()" method - this ensures you only have provide the "Story" once and it will be reused across all the scenarios within this test class.
    2. The Story defined in DescribeFeature() is available to the test via the "Feature" property.
  3. Create a "domain" class and put the StoryQ delegates in it....the magic ingredient is to inherit from TripleA.StoryQ.StoryQTestDomain.
    1. This provides a property called "TripleA" to your domain class - all the TripleA extension methods will be available to your "domain" from here.

The "domain" should be created once per test within a using statement (this ensures the Dispose() method of the StoryQTestDomain is run) - this also provides isolation - whatever state you maintain in the domain is destroyed between tests.
[TestFixture]
public class Version123DeploymentTests : BddFeature
{
    // DescribeFeature method has to be implemented - this allows the "Story"
    // to be defined only once rather than repeated per test.

    [Test]
    public void NewUserRoleDeployed()
    {
         using (var domain = new DeploymentDomain())
         {
              Feature.WithScenario("report_reader role has been deployed")
                  .Given(domain.ThatRelease_HasBeenDeployed, "1.2.3")
                  .When(domain.TheDatabaseIsCheckedForTheRole_, "report_reader")
                     .And(domain.TheUser_IsInRole_, "svc_ReportingService", "report_reader")
                  .Then(??????)
                  .ExecuteWithReport();
         }
    }
}
...and the "domain" class looks like this,
public class DeploymentDomain : StoryQTestDomain
{
    // test delegates now live here...
    public void ThatRelease_HasBeenDeployed(string version)
    {
        // assert that this release has been applied
        TripleA.AllExtensionsAreAvailableHere....!
    }

    // other delegates here...
}

Other BDD frameworks/Context Specification

In general these frameworks bring their own sequencing syntax to ensure that you can provide code to arrange, act and assert. TripleA can be used seamlessly with these frameworks...and to do this an alternative BDD ContextPipeline (Step Runner) has been created for general BDD style tests including plain old "Context Specification" style.

The difference with this pipeline to the regular one is that instead of you fluently configuring all the steps then executing them in one hit sequentially within a test method it allows you to define the pipeline and context to use up front (on say your "Given/Setup" method) then in each BDD step method you only set up the extension call that implements the method intent; as soon as you call the extension it will clear down the "ContextPipeline", add the one you want and immediately execute it for you.

An example will illustrate the difference....first the traditional in-line approach...
public class TraditionalApproachStandardContextPipelineTesting
{
    [Test]
    public void AssertsTheApplicationServiceIsInstalledCorrectly()
    {
        const string serviceName = "SomeService";

        // three tests about our service are run sequentially and the step results
        // are displayed and asserted once all complete
        var session = TripleA.Core.Session.Setup(x => x.ServiceInstalled(serviceName)
                .ServiceIsRunningAsIdentity(serviceName, @"DOMAIN\svc-Bob")
                .ServiceStatus(serviceName, ServiceControllerStatus.Running));
        var results = session.Execute(new TripleA.Core.Interfaces.Entities.Context());

        results.Dump();
            
        Assert.IsTrue(results.Success);
    }
}

Same tests arranged with "Context Specification"...

namespace ContextSpecificationAppServiceInstallation
{
    // allows partitioning across different target areas...db, filesystem
    namespace SCM
    {
        [TestFixture]
        public class WhenTheApplicationServiceIsDeployed
        {		
            private const string ServiceName = "SomeService";
			
            private BddPipelineConfig<TripleA.Core.Interfaces.Entities.Context> _tripleA;
            private TripleA.Core.Interfaces.Entities.Context _context;

            [TestFixtureSetUp]
            public void Given()
            {
                // note we create an empty explicit BddPipelineConfig...no fancy Setup required....
                _context = new TripleA.Core.Interfaces.Entities.Context();
                _tripleA = new BddPipelineConfig<TripleA.Core.Interfaces.Entities.Context>(_context);
            }

            [Test]
            public void ThenTheWindowsServiceShouldExist()
            {
                // ...in each case the tripleA "session" is emptied of previous steps
                // and the new step added is instantly executed and if fails will throw
                // an exception to terminate the wider context of the tests.
                _tripleA.ServiceInstalled(ServiceName);
            }

            [Test]
            public void ThenTheWindowsServiceShouldHaveTheCorrectIdentity()
            {
                _tripleA.ServiceIsRunningAsIdentity(ServiceName, @"DOMAIN\svc-Bob");
            }

            [Test]
            public void ThenTheWindowsServiceShouldBeStarted()
            {
                _tripleA.ServiceStatus(ServiceName, ServiceControllerStatus.Running);
            }
        }
    }
}
The benefit of this approach is that you get a much clearer test output as the tests are broken into individual tests/assertions making it easier to see what has failed (of course you could easily arrange your traditional tests to perform only one assertion per test), but the "bundling" of tests with Context Specification around the "When" class pattern is pretty strong.


Last edited Oct 24, 2014 at 5:32 PM by jimbobdog, version 21

Comments

No comments yet.