views:

1128

answers:

19

I know that one of the defining principles of Test driven development is that you write your Unit tests first and then write code to pass those unit tests, but is it necessary to do it this way?

I've found that I often don't know what I am testing until I've written it, mainly because the past couple of projects I've worked on have more evolved from a proof of concept rather than been designed.

I've tried to write my unit tests before and it can be useful, but it doesn't seem natural to me.

+2  A: 

Not always, but I find that it really does help when I do.

Paul Croarkin
+2  A: 

I tend to write them as I write my code. At most I will write the tests for if the class/module exists before I write it.

I don't plan far enough ahead in that much detail to write a test earlier than the code it is going to test.

I don't know if this is a flaw in my thinking or method's or just TIMTOWTDI.

J.J.
TIMTOWTD? what on earth is that?
Omar Kooheji
There is more than one way to do it. Code + Tests about the same time can still be test-driven. Rough out the code, write good tests, finish the code.
S.Lott
A: 

I don't write the actual unit tests first, but I do make a test matrix before I start coding listing all the possible scenarios that will have to be tested. I also make a list of cases that will have to be tested when a change is made to any part of the program as part of regression testing that will cover most of the basic scenarios in the application in addition to fully testing the bit of code that changed.

Elie
+6  A: 

There have been studies that show that unit tests written after the code has been written are better tests. The caveat though is that people don't tend to write them after the event. So TDD is a good compromise as at least the tests get written.

So if you write tests after you have written code, good for you, I'd suggest you stick at it.

I tend to find that I do a mixture. The more I understand the requirements, the more tests I can write up front. When the requirements - or my understanding of the problem - are weak, I tend to write tests afterwards.

David Arno
can you please provide links to the studies? Thanks
Miau
The link in this answer points to a blog post questioning the study results, not to actual studies with different results. I'd discount the validity of the first line of this answer as a result.
Scott A. Lawrence
The link points to a detailed analysis of the conclusions the study's team drew and the reasons why their conclusions were wrong. The study actually clearly showed that test after is better than test before (just so long as it is carried out)
David Arno
+2  A: 

I start with how I would like to call my "unit" and make it compile. like:

picker = Pick.new
item=picker.pick('a')
assert item

then I create

class Pick
 def pick(something)
 return nil
 end
end

then I keep on using the Pick in my "test" case so I could see how I would like it to be called and how I would treat different kinds of behavior. Whenever I realize I could have trouble on some boundaries or some kind of error/exception I try to get it to fire and get an new test case.

So, in short. Yes. The ratio doing test before is a lot higher than not doing it.

Jonke
A: 

Remember with Extreme programming your tests effectly are you documenation. So if you don't know what you're testing, then you don't know what you want your application is going to do?

You can start off with "Stories" which might be something like

"Users can Get list of Questions"

Then as you start writing code to solve the unit tests. To solve the above you'll need at least a User and question class. So then you can start thinking about the fields:

"User Class Has Name DOB Address TelNo Locked Fields"

etc. Hope it helps.

Crafty

CraftyFella
A: 

Yes, if you are using true TDD principles. Otherwise, as long as you're writing the unit-tests, you're doing better than most.

In my experience, it is usually easier to write the tests before the code, because by doing it that way you give yourself a simple debugging tool to use as you write the code.

chills42
A: 

I write them at the same time. I create the skeleton code for the new class and the test class, and then I write a test for some functionality (which then helps me to see how I want the new object to be called), and implement it in the code.

Usually, I don't end up with elegant code the first time around, it's normally quite hacky. But once all the tests are working, you can refactor away until you end up with something pretty neat, tidy and proveable to be rock solid.

JamShady
+19  A: 

Some good comments here, but I think that one thing is getting ignored.

writing tests first drives your design. This is an important step. If you write the tests "at the same time" or "soon after" you might be missing some design benefits of doing TDD in micro steps.

It feels really cheesy at first, but it's amazing to watch things unfold before your eyes into a design that you didn't think of originally. I've seen it happen.

TDD is hard, and it's not for everybody. But if you already embrace unit testing, then try it out for a month and see what it does to your design and productivity.

You spend less time in the debugger and more time thinking about outside-in design. Those are two gigantic pluses in my book.

Ben Scheirman
How do you create Unit Test first? The IDE will pop a lot of warning and error and the intellisence won't work! I do not see how to do it.
Pokus
Let the IDE generate the method stub. All the test will fail at first.
flukus
@Pokus - the quick answer is... I turn on auto-statement completion off so that intellisense doesn't get in my way. CTRL+space will always bring it up if I need it.I'd highly recommend ReSharper (http://jetbrains.com/resharper). It aids my TDD workflow heavily.
Ben Scheirman
I think the idea is that you write an interfae first and implements it with stubs that (in C#) throw not implemented exceptions.All your tests will fail and writing your code will make the tests pass one by one.
Omar Kooheji
@Ben - you can clear the list of characters that will commit from the autocomplete list; then only TAB will do it. Best of both worlds.
Jay Bazuzi
That's a good tip, Jay!
Ben Scheirman
+1  A: 

I think writing the test first helps define what the code should actually do. Too many times people don't have a good definition of what the code is suppose to do. They simply start writing and make it up as they go along. Creating the test first makes you focus on what the code will do.

Jim C
+1  A: 

Writing the tests first defines how your code will look like - i.e. it tends to make your code more modular and testable, so you do not create a "bloat" methods with very complex and overlapping functionality. This also helps to isolate all core functionality in separate methods for easier testing.

Sunny
+5  A: 

TDD is not about the tests, but how the tests drive your code. So basically you are writing tests to let an architecture evolve naturally (and don't forget to refactor !!! otherwise you won't get much benefit out of it). That you have an arsenal of regression tests and executable documentation afterwards is a nice sideeffect, but not the main reason behind TDD.

So my vote is: Test first

PS: And no, that doesn't mean that you don't have to plan your architecture before, but that you might rethink it if the tests tell you to do so !!!!

+1  A: 

Directives are suggestion on how you could do things to improve the overall quality or productivity or even both of the end product. They are in no ways laws to be obeyed less you get smitten in a flash by the god of proper coding practice.

Here's my compromise on the take and I found it quite useful and productive.

Usually the hardest part to get right are the requirements and right behind it the usability of your class, API, package... Then is the actual implementation.

  1. Write your interfaces (they will change, but will go a long way in knowing WHAT has to be done)
  2. Write a simple program to use the interfaces (them stupid main). This goes a long way in determining the HOW it is going to be used (go back to 1 as often as needed)
  3. Write tests on the interface (The bit I integrated from TDD, again go back to 1 as often as needed)
  4. write the actual code behind the interfaces
  5. write tests on the classes and the actual implementation, use a coverage tool to make sure you do not forget weid execution paths

So, yes I write tests before coding but never before I figured out what needs to be done with a certain level of details. These are usually high level tests and only treat the whole as a black box. Usually will remain as integration tests and will not change much once the interfaces have stabilized.

Then I write a bunch of tests (unit tests) on the implementation behind it, these will be much more detailed and will change often as the implementation evolves, as it get's optimized and expanded.

Is this strictly speaking TDD ? Extreme ? Agile...? whatever... ? I don't know, and frankly I don't care. It works for me. I adjust it as needs go and as my understanding of software development practice evolve.

my 2 cent

Newtopian
+5  A: 

I've lead development teams for the past 6-7 years. What I can tell for sure is that as a developer and the developers I have worked with, it makes a phenomenal difference in the quality of the code if we know where our code fits into the big picture.

Test Driven Development (TDD) helps us answer "What?" before we answer "How?" and it makes a big difference.

I understand why there may be apprehensions about not following it in PoC type of development/architect work. And you are right it may not make a complete sense to follow this process. At the same time, I would like to emphasize that TDD is a process that falls in the Development Phase (I know it sounds obsolete, but you get the point :) when the low level specification are clear.

a-sak
+1  A: 

Personally, I believe unit tests lose a lot of their effectiveness if not done before writing the code.

The age old problem with testing is that no matter how hard we think about it, we will never come up with every possibly scenario to write a test to cover.

Obviously unit testing itself doesn't prevent this completely, as it restrictive testing, looking at only one unit of code not covering the interactions between this code and everything else, but it provides a good basis for writing clean code in the first place that should at least restrict the chances for issues of interaction between modules. I've always worked to the principle of keeping code as simple as it possibly can be - infact I believe this is one of the key principles of TDD.

So starting off with a test that basically says you can create a class of this type and build it up, in theory, writing a test for every line of code or at least covering every route through a particular piece of code. Designing as you go! Obviously based on a rough-up-front design produced initially, to give you a framework to work to.

As you say it is very unnatural to start with and can seem like a waste of time, but I've seen myself first hand that it pays off in the long run when defects stats come through and show the modules that were fully written using TDD have far lower defects over time than others.

Adam Cobb
+2  A: 

I've been programming for 20 years, and I've virtually never written a line of code that I didn't run some kind of unit test on--Honestly I know people do it all the time, but how someone can ship a line of code that hasn't had some kind of test run on it is beyond me.

Often if there is no test framework in place I just write a main() into each class I write. It adds a little cruft to your app, but someone can always delete it (or comment it out) if they want I guess. I really wish there was just a test() method in your class that would automatically compile out for release builds--I love my test method being in the same file as my code...

So I've done both Test Driven Development and Tested development. I can tell you that TDD can really help when you are a starting programmer. It helps you learn to view your code "From outside" which is one of the most important lessons a programmer can learn.

TDD also helps you get going when you are stuck. You can just write some very small piece that you know your code has to do, then run it and fix it--it gets addictive.

On the other hand, when you are adding to existing code and know pretty much exactly what you want, it's a toss-up. Your "Other code" often tests your new code in place. You still need to be sure you test each path, but you get a good coverage just by running the tests from the front-end (except for dynamic languages--for those you really should have unit tests for everything no matter what).

By the way, when I was on a fairly large Ruby/Rails project we had a very high % of test coverage. We refactored a major, central model class into two classes. It would have taken us two days, but with all the tests we had to refactor it ended up closer to two weeks. Tests are NOT completely free.

Bill K
A: 

It helps when you are writing something that you are used writing to write first all the thing you would regularly check for and then write those features. More times then not those features are the most important for the piece of software you are writing. Now , on the other side there are not silver bullets and thing should never be followed to the letter. Developer judgment plays a big role in the decision of using test driven development versus test latter development.

Nikola Stjelja
A: 

Before, during and after. Before is part of the spec, the contract, the definition of the work During is when special cases, bad data, exceptions are uncovered while implementing. After is maintenance, evolution, change, new requirements.

dongilmore
+1  A: 

I'm not sure, but from your description I sense that there might be a misunderstanding on what test-first actually means. It does not mean that you write all your tests first. It does mean that you have a very tight cycle of

  1. write a single, minimal test
  2. make the test pass by writing the minimal production code necessary
  3. write the next test that will fail
  4. make all the existing tests pass by changing the existing production code in the simplest possible way
  5. refactor the code (both test and production!) so that it doesn't contain duplication and is expressive
  6. continue with 3. until you can't think of another sensible test

One cycle (3-5) typically just takes a couple of minutes. Using this technique, you actually evolve the design while you write your tests and production code in parallel. There is not much up front design involved at all.

On the question of it being "necessary" - no, it obviously isn't. There have been uncountable projects successfull without doing TDD. But there is some strong evidence out there that using TDD typically leads to significantly higher quality, often without negative impact on productivity. And it's fun, too!

Oh, and regarding it not feeling "natural", it's just a matter of what you are used to. I know people who are quite addicted to getting a green bar (the typical xUnit sign for "all tests passing") every couple of minutes.

Ilja Preuß