Applied TDD – How to make every ‘user story’ a ‘success story’

posted in: AngularJS, Design, Standards, Testing | 0

How to make every ‘user story’ a ‘success story’ is what we are about. We spend a lot of time grooming the backlog and collecting user stories. What we have always missed is how to link the sprint backlog to the actual work being performed.

Here is an idea as POC of how we can go about doing that.

We write our tests before we write the code. Instead of just using testing to verify our work after it’s done, TDD turns testing into a design activity. We use the tests to clarify our ideas about what we want the code to do.

Screen Shot 2014-06-06 at 8.26.07 AM

The illustration above shows the nested loops in their simplest form. “Unit” test  can be replaced with “End to End” (e2e) and  “Integration”. The nature of the loops remains regardless of the nature of the test.

In fact, it helps if one sees the tests as nested too, but it does not apply generally, so we will skip that proposal for now.

We use Jasmine for e2e, integration and unit test descriptions. http://jasmine.github.io/2.0/introduction.html?

Screen Shot 2014-06-06 at 12.44.03 AM

Example test suite code:

As a student I would like to play music with my 'Player'

   Player
      should be able to play a Song

      when song has been paused
         should indicate that the song is currently paused
         should be possible to resume

      tells the current song if the user has made it a favorite

      #resume
         should throw an exception if song is already playing

 

 

Bringing the report and the agile experience together.

 

If we write our User Stories into these tests the report could play an entirely different role. If we see our tests as automated feedback to all the stakeholders of the project our test suite will look and act differently.

 

Notice: the feedback has a ‘nested’ structure.

To the Product Owner it feeds back: 1

  • How the User Stories are being fulfilled by functional design objectives
  • How the Domain Model is being applied to the architecture
  • Which features are complete and how that fits in the Domain and claims to satisfy the User requirements

To the Architect it feeds back: 2

  • How the User Stories are connected to the Domain Model
  • How the Domain Model is being applied to the architecture
  • Which functional design objectives are complete and how that relates to the Architecture components

To the Development Team it feeds back: 3

  • How the User Stories are being fulfilled by functional design objectives
  • How the Domain Model provides conceptual structure for code base organisation
  • Which functional design objectives are complete and what progress is being made toward completing a feature

 

I noticed that Jasmine can ‘nest’ its tests and assertions. That made me wonder if we cannot connect the ‘nested’ test loops to a single ‘nested’ reporting interface.

Example Report – Feedback:

[user story] As a User I would like to interact with a 'Thing'

   [component in the domain model or architecture] Thing
   
      [functional spec] should have a message property with value 'Thing exists!'
      [functional spec] should have a function 'task' that returns 'true'
      [functional spec] must have or do the following

 

Finally the POC functionality may look something like this:

describe("[user story] As a User I would like to interact with a 'Thing'", function () {

    describe("[component in the domain model or architecture] Thing", function () {

        var thing

        beforeEach(function () {
            thing = new Thing()
        })

        it("[functional spec] should have a message property with value 'Thing exists!'", function() {
            expect(thing.message).toMatch("Thing exists!")
        })

        it("[functional spec] should have a function 'task' that returns 'true'", function() {
            expect(thing.task()).toBeTruthy()
        })

        it("[functional spec] must have or do the following", function () {
            expect(true).toEqual(true)
        })

    })

    it("[component passes integration tests] the 'Thing' works in the system", function () {
        expect(true).toEqual(true)
    })

    it("[success story] the simulated 'User' can use it", function () {
        expect(true).toEqual(true)
    })

})

 

The interface may look something like this:

Screen Shot 2014-06-06 at 9.02.21 AM

 

After some work emulating a design session we have this:

describe("As a pet owner I would like the vet to see my pets details after typing in its name in the search box", function () {

    describe( 'e2e: search for a pet', function() {

        it("test result", function () {
            expect(true).toEqual(true)
        })

    })

    describe("frontend :: from the pet owner display {search} for a {pet}", function () {

        it("test result", function () {
            expect(true).toEqual(true)
        })

        describe("integration :: after choosing my [pet owner account] the search for my [pets] works", function () {

            it("test result", function () {
                expect(true).toEqual(true)
            })

            describe("unit :: [pet controller]", function () {

                it("test result", function () {
                    expect(true).toEqual(true)
                })

            })

            describe("unit :: [pet service]", function () {

                it("test result", function () {
                    expect(true).toEqual(true)
                })

            })

        })

        describe("integration :: [pet module] controller calls [pet service]", function () {

        })

    })

    describe("backend :: securely respond to a GET request to endpoint ./pet", function () {

        it("test result", function () {
            expect(true).toEqual(true)
        })

        describe("integration :: api ./pet/1 endpoint responds with [pet] json", function () {

            it("test result", function () {
                expect(true).toEqual(true)
            })

            describe("unit :: [pet controller]", function () {

                it("test result", function () {
                    expect(true).toEqual(true)
                })

            })

            describe("unit :: [pet service]", function () {

                it("test result", function () {
                    expect(true).toEqual(true)
                })

            })

        })

    })

})

Which produces the following status display:

Screen Shot 2014-06-06 at 12.40.14 PM

Leave a Reply