14. "The deeper I got into TDD, the more I felt that my own journey had been less of a wax-on, wax-off process of gradual mastery than a series of blind alleys." - Dan North
36. Resources (Cont’d) Growing Object-Oriented Software, Guided by Tests by Steve Freeman and Nat Pryce :: http://amzn.to/atddbook How TDD Works (and More!) :: http://bit.ly/jbrainsTDD
We’ll Start by talking about Queuing Theory, and how it helps us explain the rationale for TDD. Then, I’ll move into talking about (x)DD processes, and my experiences with them, how I started with TDD in my own practice, moved into BDD and finally to ATDD using SpecFlow and WatiN.
11 Years of Experience. Last two years as Software Architect and dev, delivered 6 ASP.NET MVC applications into production.
Consider this presentation a case study, and not a collection of “best practices.” These are my practices, opinions, etc. Not best practices. I’m probably going to say some things you disagree with in this presentation. And I’m probably going to treat terms in ways that might be different than how you understand them.The world of (x)DD is a fragmented and contentious one, and I’m aware of the many vocal disagreements. But I don’t want to continue them here. I’m not trying to define new terms, or tell you how you should be practicing TDD. I’m merely here to share ideas from my learning and practice, and submit them for discussion. We’ll have time for you to discuss areas where your understanding might be different than mine, and I want to give you time to share that, so please speak up if you have something to share (at the end maybe).
Photo courtesy of: http://www.flickr.com/photos/chrisschuepp/2273448091/Quote from “Theory of Constraints,” by Eliyahu M. Goldratt, p. 3My own practice in TDD has evolved over the last several years. I want to share how my thinking about test-first development has changed, and has led me to the process and tools I use today. Rather than gloming into a new process and sticking with it to the death, I always try to question what I’m learning and find out where I’m still failing.
Photo courtesy of: http://www.flickr.com/photos/wiemann/1521876735/All of this started for me by asking what the goal of software development is. I’m a big proponent of Eli Goldratt’s writings around the Theory of Constrains. Goldratt defines a constraint as “anything that limits a system from achieving higher performance versus the goal.” We have do start by defining the goal.“The objective is to deliver what the customer wanted while optimizing quality; the broader goal is to create value” – Jim Coplein=> Create value for someone deliver something they wantoptimize for qualityIf this is an accurate statement, then system constraints are anything that hamper our ability to create value and optomize for quality
Photo courtesy of: http://www.flickr.com/photos/butterflysha/140523563/Let’s look at a line at a basketball arena as an example. I was at a Spurs game last season, and I noticed something. I was used to going through the ticket checker, then the bag-checker. This was obviously a bottleneck in the process. What’s more, if someone had contraband in their bag, they had two choices: 1) throw the item away or 2) take the item back to their car and return through the line.On this occasion, the bag checker was out in front of the line, which sped up the process, and kept some people from going through the line twice. In terms of the Goal, the bag checker was a constraint. A constraint that was removed by moving the back checker before the ticket checker.
Photo courtesy of: http://www.flickr.com/photos/pasukaru76/4656741022/The reason that moving the bag checker to the front of the line worked can be explained by queuing theory.Queuing Theory is the study of lines (arrival times, wait times, etc.) If you’ve done any research into Lean Software development, Queuing Theory probably sounds familiar. I’m not going to cover all of QT, but I did want to talk about a subset of Queueing Theory that relates to the Theory of Constraints: “Given a process B, which follows a process A, sometimes in performing B we need to perform some of A again. We can remove the need to rework by taking some portion of process B and performing it before process A”The idea is that we remove rework in a process by moving some piece of the process to the front of the system; This relates to one of the five focusing steps in ToC, to subvert all aspects of a system to the constraint
So what does this mean for Software development? Assume A is development and B is testing. Suppose that when we test after development, 20% of the work is defective and has to be sent back to the front of the line.
Move bottlenecks to the front of the line; In ToC, one of the five focusing steps is to subvert all constrains in the system to a bottleneck.Rework is a bottleneck, so we move testing to the front of the lineInterestingly enough, this looks a lot like…
Image from : Growing Object-Oriented Software, Guided by Tests by Steve Freeman and Nat Pryce :: http://amzn.to/atddbookThis, doesn’t it?The thing to note here is that TDD does have a basis in theory and practice, and was not conceived as a way to make money or be interesting. It’s not witchcraft, it’s a process rooted in mathematical studies and systems theory.
Photo Courtesy of : http://www.flickr.com/photos/mikebaird/3823658879/So this explains that theory behind TDD, but what does it look like? This is going to be one of those first points of divergence, and I know that most of us have our own ways of doing this, so just bear with me. This is an exercise.Tests using the [MethodName]_[StateUnderTest]_[ExpectedBehavior] patternTest class using the [Object]Tests pattern
Photo courtesy of: http://www.flickr.com/photos/martinofranchi/2891200283/So that’s great, and it certainly helped me get started with test-first development. But is my method perfect? No, it has these problems:Looks like I'm specifying an APIToo easy to start speculating on features I may or may not need as I’m “in the groove”High-coupling between my app structure and test structure (RepositoryTests;Update_WithInvalidCustomer_ShouldDeleteCustomer)Teasing apart objects would require test refactroing as well; Not a bad thing to refactor tests, but that will happen anyway. Avoid superfluous couplingProblem with grouping by ObjectTest count spins out of control. Too much to manage. I would find myself abandoning my method when deadlines neared.Maybe that is all just my problem, or maybe not…
Photo courtesy of : http://www.flickr.com/photos/wolfrage/3932030126/From :: http://blog.dannorth.net/introducing-bdd/Dan North appeared to experience some of the same issues in his practice with TDD. Many of the reasons I listed in the last slide are ones that led Dan to adjust his practice of TDD, and then coin the term BDD to describe them.
The shift that North proposed is summarized in the statement “working software that matters.” His assertion is that TDD leads us to working software, but is it working software that matters?Consider the example of the CustomerRepository. It was possible to delete a customer record, but does it matter if delete isn’t implemented in the UI?
The first step in that shift is to focus on actual behaviors. What the software really needs to do to meet the goal. That is, to deliver value to someone.So rather than getting bogged down into constructing an API, we have to think about how the software is to be used by a human.Moving from APIs to Behaviors Change in syntax of the testsThe benefit this gives me in staying focused
Photo courtesy of: http://www.flickr.com/photos/sookie/1490738885/If you see BDD-style unit tests, you’ll likely notice 2 things:The test context is finer-grained. Maybe not even 1 test class per object, but test per context of the SUT.Use of the word should as a part of every method name.Some people tend to minimize should, as just a name change that doesn’t mean anything. Dan Brown argues, and I agree (though perhaps I’m being touchy-feely) that should is also psychological. Should allows the software to be questioned Should is about design and intent, and it helps you think through the behavior, not just an assertion.
Photo Courtesy of : http://www.flickr.com/photos/mikebaird/3823658879/Again, this is just an example of how this type of testing could be done, and how I’ve done it in the past.Changing Test Class and Method Structure around Shouldthe transition from tdd to bddb#.website http://flux88.com/blog/the-transition-from-tdd-to-bdd/You could also refer to this as small-scale BDD. I say small scale, because this is a bdd shift, but limited in focus. ATDD is more of a large-scale BDD focus
Photo courtesy of: http://www.flickr.com/photos/martinofranchi/2891200283/So this is great, but is it perfect? For those of you who have done this style of testing in the past, what’s wrong with it? Still difficult to know where to start. I still only have a line on a backlog, most of the time (though this is not always the case)Tests are still expressed in the language of the technology Prone to misunderstandingThere’s still rework!!! (Next slide)The tests I write don’t save me from rework that comes in acceptance testing, customer testing, demos, etc. About that acceptance testing rework…
Photo courtesy of: http://www.flickr.com/photos/butterflysha/140523563/Remember, queuing theory states that, if rework happens from one step to the next, we can eliminate it my moving that step to the front of the line.
B = TestingA = DevelopmentC = User AcceptanceSo we assume, after a dev-test cycle, we experience 20% rework that arises from UAT
Following Queuing Theory, we can minimize rework by moving at least some of UAT to the front of the line.So we perform some level of Acceptance Testing, prior to our TDD cycle.What does this look like in reality?
Image from : Growing Object-Oriented Software, Guided by Tests by Steve Freeman and Nat Pryce :: http://amzn.to/atddbookOur first step is to write an “end-to-end test” according to Freeman and Pryce, this is an acceptance test. What does an acceptance test look like?
Feature CreationStart with the backlog items you already haveCraft a story around itThis describes value for the customerCreate one or more scenarios that describe steps needed to implement a piece of that story (feature)Implement each scenario one at a timeImplement each scenario step one at a timeThe story is done when value is implemented as described
What’s interesting about this process is that we now have tools that enable us to truly treat an acceptance test as an executable asset. You’ll see these often referred to as “executable specifications,” and they are truly that, specifications written in the language of the business that can be executing by a testing tool.This leads to a huge shift in perspective. The story is our first test, and the application itself is the entry point for testing, not a public method in a class file…In .NET, there are a few options for this kind of testing. I’m going to show of Gherkin, SpecFlow and WatiN.
You’ve probably heard of Cucumber, a BDD-style tool in Ruby that enables what I just talked about. What you might not know is that the part of Cucumber that defines Feature (story) syntax is called Gherkin. Gherkin has been implemented outside of Ruby using Ragel (a statemachine compiler that enables Gherkin to be shared across languages; http://www.complang.org/ragel/) and is used in Ruby, Java, Objective-C, C and C++. Using IKVM (www.ikvm.net), Gherkin was ported to .NET, which is what SpecFlow uses.So Cucumber, Cuke4Duke, Cuke4Nuke and SpecFlow all use the same parser for Feature files, which is nice.
SpecFlow is the tool I use to author Feature files in .NET. SpecFlow parses those files and matches each step in a scenario to a step definition in my code base (a method with a SpecFlow attribute and regular expression string in a test project). When I run my tests (using MSTest, Nunit, etc.) SpecFlow executes my step definitions to perform the test.So my plain text feature files are mapped to my executing code.
In my steps, I choose to use WatiN to help me drive the browser directly. I could test directly through my controllers (I still do that through unit tests), but I’d rather truly test end-to-end because that helps me meet my goal of delivering value and ensuring quality. If I can automatically replicate the behavior of the user, why wouldn’t I?WatiN = Drive the browser as the entry point into your applicationPurely optional and preference-based In an MVC app, you can test directly against the controllers
Image from : Growing Object-Oriented Software, Guided by Tests by Steve Freeman and Nat Pryce :: http://amzn.to/atddbookWe talked about the tools, let’s talk about where they fit before moving into a demo.The outer loop, the inner loop…
Photo Courtesy of : http://www.flickr.com/photos/mikebaird/3823658879/Changing Test Class and Method Structure around Shouldthe transition from tdd to bddb#.website http://flux88.com/blog/the-transition-from-tdd-to-bdd/I say small scale, because this is a bdd shift, but limited in focus. ATDD is more of a large-scale BDD focus
In this presentation, I’ve used TDD, BDD and ATDD to map to the evolution of my practice, but not all would use them that way.It's just a name...The process (and its ability to help you meet the goal) is what really mattersSome would say ATDD is just a subset of BDDSome would say that BDD is just TDD done right I tend to use the names to denote an evolution in my process, thinking and understanding.I’ve taken things from each, and improved my practice with each stepTDD was the startBDD shifted my thinking from tech design to domain designATDD shifted my thinking from units to features
Photo courtesy of: http://www.flickr.com/photos/wiemann/1521876735/But the key, the bottom line, is to remember the goal. In this case, the goal of any (x)DD process…
Photo courtesy of: http://failblog.org/2010/09/30/epic-fail-photos-classic-outlet-planning-fail/The goal is to minimize rework. Some % of that minimization is going to be unique to you, your company, etc. So don’t just parrot a discipline because you read a blog. Use something, adapt and iterate over it.
Photo Courtesy of: http://static.funnyjunk.com/pictures/ae5d49c5_494f_d0160.jpgAnd if you take nothing else out of this presentation, take away the knowledge that any improvement starts with a question about the status quo. My practice improved, and hopefully will continue to improve because I was willing to question my thinking. As Eli Goldratt would say, “never allow inertia to become a constraint.”