views:

1189

answers:

12

I do write unit tests while writing APIs and core functionalities. But I want to be the cool fanboy who eats, sleeps and breathes TDD and BDD. What's the best way to get started with TDD/BDD the right way? Any books, resources, frameworks, best practices?

My environment is Java backend with Grails frontend, integrated with several external web services and databases.

+4  A: 

Best practice IMHO: Do what is practical and not just because it is a process. Don't forget what the goal of writing applications is, and in the business world, it isn't writing tests. Don't get me wrong, they have their place, but that shouldn't be the goal.

People who've never done *good* TDD give this advice all the time. Sometimes they've done it, but upon further inquiry, it becomes clear that what they were doing was more like *bad* TDD, and most of their problems stem from bad practices rather than TDD itself.
Bob Aman
You got me, I, guess I've never actually done any "real" TDD. Actually, what I said was they do provide value when used correctly, but you have to be careful that your focus is on providing a solution and not JUST writing tests.
Connotations are just as important as the literal words. What you said was factually true, but that's all that can be said to commend it. Not even the die-hard TDD people think that "tests are the goal". I call strawman. The goal is reliable code, with low maintenance cost, and short development time. Tests get you there, and if you're doing TDD right, you have to be up near 80%+ coverage before you start seeing diminishing returns for additional tests. In practice, this essentially means that almost every test you write will increase your productivity in the long-run.
Bob Aman
IMHO (and the HO of a lot of people smarter than me) If you don't have tests then you simply do not have working code. Tests are not a nice to have, they are a necessity and a requirement. Unless of course you enjoy having long dev cycles, buggy code that nobody knows how it works and a entire division of QA workers.
ryber
gosh, what did we do before TDD?
@wilums2 Before we had cars, we used horse-carts. Not many people would say that a horse-cart is more effective than a car :)
Thomas Winsnes
+3  A: 

Metrics are, IMHO, the best way to get from here to there. Keep track of how well your code is covered, keep deltas of code complexity for every commit, use test-runners that watch your code for changes and constantly re-run the corresponding tests. Never let test lengths get above a few lines, so that all your tools work well. And I'd recommend once a month, take a day off to run your code through a mutation tester. That day should be dedicated to writing tests only. All of this stuff will bring you pain if you're not already doing good TDD. Learn from the pain, and in no time at all, you'll be doing it right.

And never lose sight of what the tests are for: To describe desired behavior. They are your executable specification. (This is also why I like Cucumber; now you can get your PHB to write your tests for you! Well, maybe not quite that good, but it's close!)

Bob Aman
+ 1 "And never lose sight of what the tests are for: To describe desired behavior."
Langali
Could you recommend any mutation tester?
Thorbjørn Ravn Andersen
Heckle, Pester, Jester for Ruby, Python, and Java respectively.
Bob Aman
+1 for Cucumber link, very interesting!
Thorbjørn Ravn Andersen
+1  A: 

For start do unit testing, then read about how to do it right last teach your team how to TDD and get them on board - because in my experience nothing is more important then doing unit testing with your whole team.

You'll also need a proper build process - using a build server that would build your code and run your testst I recommend using TeamCity (free with limitations).

Learning how to right good unit tests is the hard part - some of it you'll learn by yourself (as long as you keep unit testing) and the rest you can learn from searching the internet.

You'll know you've reached your goal when NOT writing unit tests as part of development will look to you just wrong.

Dror Helper
We do have a build process and some tests, but those were outsourced.
Langali
+1  A: 

Remember, agile means that you're not completely sold out on any particular method. If you're working on something where the benefits of TDD aren't worth it (like doing trial-and-error edits on a Swing interface), then don't use TDD.

Kaleb Brasee
Does TDD always have to be a part of Agile?
Langali
I thought agile meant that the we have no requirements on paper, and the project manager can come by my desk and ask me to add this little feature or that little feature whenever he felt like it.
JimN
LOL, that's what some project managers want it to be. But no.
Kaleb Brasee
+4  A: 

Find someone that has been doing TDD/BDD and pair program with them.

Jeff Waltzer
+6  A: 

I don't like it when people say "Practice X is never bad; if it doesn't work, you're not doing it right." Sorry, it has the same feel as any other over-zealous religious dogma. I don't buy it.

I agree with those folks who say that the best solution your time and money can afford should be the goal.

Anyone who objects to TDD should not automatically be accused of disregarding quality. ("So when did you stop beating your wife?") The fact is that software has bugs in it, and the cost of eliminating all of them has to be weighed against the benefit.

The same holds true in manufacturing. Tolerances on dimensions and finishes on surfaces are not all the same, because sometimes a close tolerance and a mirror finish aren't warranted.

Yes, I write unit tests, although not often before I write the class. I've seen the effect of tests on design. I measure and watch code coverage. If I find that my coverage isn't acceptable, I write more tests. I understand the benefit of a safety net of unit tests for refactoring. I follow those practices even when I'm working alone, because I've experienced the benefits first-hand. I get it.

But I'd look askance at any teammate that started bugging me about "eating, sleeping, and breathing unit testing and TDD."

My manager says that the only way that will get me a promotion is if I can get the team to TDD/BDD.

Ever think that maybe this makes you sound like a suck-up? Have you found that your nagging has alienated the rest of your team?

This response might lose me a few reputation points, but it had to be said.

I think a better approach would be to practice it yourself and let others see the benefit. Lead by example. It'll be far more persuasive than running your mouth.

Geez, Grails has test generation built-in. If you're working on a team that uses Grails, how much more selling is needed?

duffymo
+1 You won't lose a point for saying this. I was being satirical about "eating , sleeping and breathing TDD" as my manager is more obsessed with the buzzword TDD than quality of the product.
Langali
Sorry, satire and sarcasm are filtered out by my browser. I misunderstood your intent.
duffymo
Depends on *how* they object to TDD. If you were "eating, sleeping, beathing" testing, I'd say your focus is on the wrong thing. But TDD is not testing. TDD is an entire development process, and assuming that you don't mind your entire life being development, I've got no problems with someone who says they want to "eat, sleep, and beath" TDD. Sarcasm notwithstanding.
Bob Aman
BTW, there are plenty of problem domains for which TDD doesn't really work. Game development for example. You can unit test a fair amount of stuff in a game, but there's still huge swaths of code that are going to be all but untestable. This throws a wrench in the works for TDD.
Bob Aman
That said, people have still managed to do TDD even in a game development environment (mocking graphics API calls, mocking controller inputs, etc.) http://gamesfromwithin.com/backwards-is-forward-making-better-games-with-test-driven-development
Bob Aman
My personal experience has been that I get about 3x better results from TDD on library code than on web application code (my two main areas of work), so it's fair to say that the benefits of TDD are not evenly distributed. Different applications have different testing needs. However, I've yet to work on something where I felt that TDD was a waste of time. (At least since I started doing TDD well anyway; it was kind of a pain at first.)
Bob Aman
-1 for not actually answering the question
ryber
+1  A: 

"PS: My manager says that the only way that will get me a promotion is if I can get the team to TDD/BDD."

The only realistic way to get a team to do something (without killing you in the process) is to demonstrate to them clearly that it will benefit them to change their habits. In other words, write code. Lots of code. Tons of code. And then when the crucial email arrive that alters the specification radically, show them that you can change your code easily with refactoring and whats worse because you were prepared for it with your tests in place. The bar was green, hack hack hack, RED BAR!!!!, hack hack hack, green bar, go home.

Read Kent Becks book about test driven design. Start with tests and then do the code. Get a build server running which RUNS THE TESTS! You do not need ot have it for the whole team - do it for yourself and SHOW them that it helps.

Preaching only annoys natives :)

Thorbjørn Ravn Andersen
+11  A: 

A good place to start is reading blogs. Then buy the books of the people who are blogging. Some I would highly recommend:

"Uncle Bob" Martin and the guys at Object Mentor: http://blog.objectmentor.com/

P.S. get Bobs book Clean Code:

http://www.amazon.com/Clean-Code-Handbook-Software-Craftsmanship/dp/0132350882

My friend Tim Ottinger (former Object Mentor dude) http://agileinaflash.blogspot.com/ http://agileotter.blogspot.com/

The Jetbrains guys: http://www.jbrains.ca/permalink/285

I felt the need to expand on this, as everyone else seems to just want to give you their opinion of TDD and not help you on your quest to become a Jedi-Ninja. The Michael Jordan of TDD is Kent Beck. He really did write the book on it:

http://www.amazon.com/Test-Driven-Development-Kent-Beck/dp/0321146530

he also blogs at:

http://www.threeriversinstitute.org/blog/?p=29

other "famous" supporters of TDD include:

All are great people to follow. You should also consider attending some conferences like Agile 2010, or Software Craftsmanship (this year they were held at the same time in Chicago)

ryber
This is what I was looking for.
Langali
Updated with 90% more Ninjas
ryber
http://agileinaflash.blogspot.com/2009/02/meaningful-names.html is the short form. And yes, ryber is my friend.
tottinge
+1  A: 

I can't see that anybody has really expressed that TDD is not about testing. TDD-ing is about expressing the expected behaviour before doing the tiny behavioural-changing modification. This greatly improves design and enables focusing in a way I have never experienced before. You get tests that protects your future refactorings and 90% coverage for free.

To learn it I would suggest (summarising what others have said and adding one of my own):

  1. visit the blogs and read the books mentioned above
  2. pair up with someone proficient in TDD
  3. practice

I practiced the Bowling kata (exercise) on my own about 20 times (about 30 minutes apiece) before I started to see the light. Started out by analysing Uncle Bob's description of it here. There are a host of katas on the codingdojo.org site including solutions and discussions. Try them!

Thomas Nilsson
+1  A: 

To take a quote from Nike: JUST DO IT.

Second piece of advice - never rely on someone else's interface. Always write, on the level of each class, to the interface you wished existed - write up an adapter to the actual implementation as necessary.

Also, I find it useful to avoid return values on methods, and to think of the code in terms of message-passing rather than function calls.

YMMV.

kyoryu
+1  A: 

A year ago, I had little idea how to do TDD (but really wanted to (how frustrating)) and had never heard of BDD... now I do both compulsively. I have been in a .Net development environment, not Java, but I even replaced the "F5 - Run" button with a macro to either run Cucumber (BDD) or MBUnit (TDD) depending if it is a Feature/Scenario or Specification. No debugger if at all possible. $1 in the jar if you use the debugger (JOKING (sort of)).

The process is very awesome. The framework we are additionally using is by The Oracle I've been blessed to come across, and absorbing information from, and that framework he/we use is MavenThought.

Everything starts with BDD. Our BDD is straight up cucumber ontop of iron ruby.

Feature:

Scenario: .... Given I do blah...
When I do something else... Then wonderful things happen...

Scenario: ...

And that's not unit testing itself, but it drives the feature, scenario by scenario, and in turn the unit (test) specifications.. So you start on a scenario, and with each step you need to complete in the scenario it drives your TDD.

And the TDD we have been using is kind of BDD in a way, because we look at the behaviours the SUT (System Under Test) requires and one behaviour is specified per specification (class "test" file).

Example:

Here is the Specification for one behaviour: When the System Under Test is created.

There is one more specification (C# When_blah_happens class file) for another behaviour when a property changes, but that is separated out into a separate file.

using MavenThought.Commons.Testing;
using SharpTestsEx;

namespace Price.Displacement.Module.Designer.Tests.Model.Observers
{
    /// <summary>
    /// Specification when diffuser observer is created
    /// </summary>
    [ConstructorSpecification]
    public class When_diffuser_observer_is_created
        : DiffuserObserverSpecification
    {
        /// <summary>
        /// Checks the diffuser injection
        /// </summary>
        [It]
        public void Should_return_the_injected_diffuser()
        {
            Sut.Diffuser.Should().Be.SameInstanceAs(this.ConcreteDiffuser);
        }
    }
}

This is probably the simplest behaviour for a SUT, because in this case when it is created, the Diffuser property should be the same as the injected diffuser. I had to use a Concrete Diffuser instead of a Mock because in this case the Diffuser is a Core/Domain object and has no property notification for the interface. 95% of the time we refer to all our dependencies like Dep(), instead of injecting the real thing.

Often we have more than one [It] Should_do_xyz(), and sometimes a fair bit of setup like perhaps upto 10 lines of stubbing. This is just a very simple example with no GivenThat() or AndGivenThatAfterCreated() in that specification.

For setup of each specification we generally only ever need to override a couple methods of the specification:

GivenThat() ==> this happens before the SUT is created.

CreatSut() ==> We auto mock creation of the sut with StructureMap and 90% of time never need to override this, but if you are constructor injecting a Concrete, you have to override this.

AndGivenThatAfterCreated() => this happens after the SUT is created.

WhenIRun() => unless it is a [ConstructorSpecification] we use this to run ONE line of code that is the behaviour we are specifiying for the SUT

Also, if there is common behaviour of two or more specifications of the same SUT, we move that into the base specifcation.

All I gotta do to run the Specification is highlight it's name, example "When_diffuser_observer_is_created" and press F5, because remember, for me F5 runs a Rake task either test:feature[tag] if Cucumber, or test:class[SUT]. Makes sense to me because everytime you run the debugger it's a throw away, no code is created (oh and it costs a $1 (joking)).

This is a very, very clean way of specifying behaviour with TDD and having really, really simple SUTs and simple specifications. If you try and be cowboy coder and write the SUT crappy with hard dependencies, etc, you will feel the pain of trying to do TDD and get fed up / give up OR bite the bullet and do it right.

And here's the actual SUT. We got a little fancy and use PostSharp to add property notify changed on the Diffuser, so hence the Post.Cast<>. And again, that's why I injected a Concrete rather than Mock. Anyway, as you can see the missing behaviour defined in another specification is when anything changes on the Diffuser.

using System.ComponentModel;
using MavenThought.Commons.Events;
using PostSharp;
using Price.Displacement.Core.Products;
using Price.Displacement.Domain;

namespace Price.Displacement.Desktop.Module.Designer.Model.Observers
{
    /// <summary>
    /// Implementation of current observer for the selected product
    /// </summary>
    public class DiffuserObserver : AbstractNotifyPropertyChanged, IDiffuserObserver
    {
        /// <summary>
        /// gets the diffuser
        /// </summary>
        public IDiffuser Diffuser { get; private set; }

        /// <summary>
        /// Initialize with a diffuser
        /// </summary>
        /// <param name="diffuser">The diffuser to observe</param>
        public void Initialize(IDiffuser diffuser)
        {
            this.Diffuser = diffuser;
            this.NotifyInterface().PropertyChanged += (x, e) => this.OnPropertyChanged(e.PropertyName);
        }

        /// <summary>
        /// Gets the notify interface to use
        /// </summary>
        /// <returns>The instance of notify property changed interface</returns>
        protected INotifyPropertyChanged NotifyInterface()
        {
            return Post.Cast<Diffuser, INotifyPropertyChanged>((Diffuser)Diffuser);
        }
    }
}

In conclusion, this BDD / TDD style of development rocks. It took one year but I am a total convert as a way of life. I would not have learned this on my own. I picked up everything from The Oracle http://orthocoders.com/.

Red or Blue pill, the choice is yours.

Sean B
+1  A: 

I've been doing TDD for a couple of years, but lately I've started looking more in to the BDD way of driving my design and development. Resources that helped me get started on BDD was first and formost Dan North's blog (the 'founder' of BDD). Take a look at Introducing BDD. There's also an 'official' BDD Wiki over at behaviour-driven.org with some good post well worth reading.

The one thing that I found really hard when starting out with BDD (and still find a bit hard) is how to formulate those scenarios to make them suitable to BDD. Scott Bellware is a man well skilled in BDD (or Context-Spesification as he like to coin it) and his article Behavior-Driven Development in Code Magazine helped me a lot on understanding the BDD way of thinking and formulating user stories.

I would also recomend the TekPub screencast Behavior-driven Design with Specflow by Rob Conery. A great intro to BDD and to a tool (SpecFlow) very good suited for doing BDD in C#.

As for TDD resources, there's already a lot of good recommendations here. But I just want to point out a couple of books that I can really recommend;

Kjetil Klaussen