views:

1136

answers:

16

I have been reading about Agile, XP methodologies and TDDs.

I have been in projects which states it needs to do TDD, but most of the tests are somehow integration tests or during the course of project TDD is forgotten in effort to finish codes faster.

So, as far as my case goes, I have written unit tests, but I find myself going to start writing code first instead of writing a test. I feel there's a thought / design / paradigm change which is actually huge. So, though one really believes in TDD, you actually end up going back old style because of time pressure / project deliverables.

I have few classes where I have pure unit tested code, but I can't seem to continue with the process, when mocks come into picture. Also, I see at times : "isn't it too trivial to write a test for it" syndrome.

How do you guys think I should handle this?

+1  A: 

Buy "Test Driven Development: By Example" by Kent Beck, and read it.

Then, write a failing unit test.

John Saunders
There is truth in this statement. For some that works. The asker has said he's already read a lot of stuff about this topic, though...
@Max: that's why I suggested he buy that book. It's what knocked TDD into _my_ head.
John Saunders
@John: Different strokes for different folks.
+4  A: 

Discipline.

Make the decision to use TDD and stick to it, it's entirely a matter of your own ability to commit to a process and see it through to a conclusion.

Fraser Graham
Yes. It is a discipline, of course, and that means that you must be a disciplined person to learn it. I think, though, that learning a discipline requires a lot of motivation and the real crux of this question is "how does one motivate oneself to have the discipline required to learn and implement this stuff?"
Yeah, that's the hard part right? There's no one answer to that - everyone is different.
Fraser Graham
Yes there is no one answer to how to motivate people. We can still get them focused on the problem of motivation, though, right?
Yes, and there are lots of good ways to motivate people to use TDD and stick to it. It's just a matter of finding what motivates you and your team.
Fraser Graham
+1  A: 

TDD is really a good practice (But at the same time I don't think that we should try to achieve 100% code coverage).

It's main advantages are:

  1. It makes developer think about the API because he needs to use that API first to write tests. At this step it's very easy to feel that something wrong with your API (bad method's names, to many lines are required for most common operations, too many odd checked exceptions or contrariwise user have no possibility to handle presumable exceptions). And you can improve it and change it as you like because nobody has used it yet.

  2. You think about how your methods should work. This often opens some implicit problems or misunderstandings at early steps.

  3. When you have tests you have a nice way to measure percentage of completed work (i.e. if you have 20 tests and 15 of them are passed then 75% of work is finished). It's more important for you as a developer than for you team or process. You just divide the whole task into many smaller tasks (e.g. 20) and can compete them one after another. It's much more pleasant than to take on the whole thing.

  4. Tests allow you to play with the code. You can do refactoring, you can improve performance etc. And again, even if you won't do it anyway it's very nicely to realize that you have the possibility to do that. It's kinda confidence that everything is fine.

How to make yourself to do TDD? You don't need! If you want to gain all listed benefits then you won't make yourself - you'll just do TDD with pleasure and of your free will. If you don't need/want/able to gain them - don't do it now.

Roman
Test-First is a practice. TDD is a discipline.
A: 

IMO, TDD with test / code / refactor - sounds great & fun but:

  • there is no hard-rule that it has to be done in that sequence
  • Many times, I found myself writing the code & then writing the tests & finding interesting nuggets which I missed
  • Other times, I went test > code > refactor cycle & enjoyed it all the same.
  • I think the important aspect is to have unit-tested code & enough coverage to ensure that all the important paths are covered. The order of achieving it is not so critical.

HTH.

EDIT: To clarify my points further

  • Although I prefer by starting with writing tests, sometimes it is easier to understand the landscape by writing code (especially for new functionality and/or new projects) & then writing tests
  • But, if I am refactoring code and/or fixing bugs, I will first check if tests are written & they sufficiently cover what the peice of code is doing. If not, first I will write the test & then do the refactoring.
Sunny
The process - the discipline - of TDD should, in fact, be done all of the time but TDD is not about when you write an automated test - that's test first. Getting high unit test coverage is only a small part of TDD - merely one of the benefits. Getting a suite of tests that serve as true _executable_ _specifications_ is a much broader umbrella that captures a lot of the value delivered by true TDD but not all of it.
-1: If you're doing TDD, then you need to write the test first, period.
John Saunders
@John: Does the test have to be automated?
@Max: I'd say yes. Otherwise how will you rerun it after changes?
John Saunders
Sunny
@MaxGuernseyll - I agree with John that the test need to be automated
Sunny
@Sunny: if it's test **driven** development, then the code is only created as a result of a failing unit test.
John Saunders
Stephane
A: 

TDD is not so much about writing tests first. If all you want is to write your tests first, then you want the Test-First Technique. The problem is that the Test-First technique in a vacuum (without TDD) ends up decaying into something that is almost worse than having no tests at all.

You said what your problem was yourself:

or during the course of project TDD is forgotten in effort to finish codes faster

Yet, if you were doing TDD, and recognizing all the value it had to offer, your team would understand that it is impossible to get code done faster without TDD as it is what makes the process of programming fast in the first place.

My suggestion is to spend some time understanding the value it can give you by recognizing the kinds of artifacts that a good test can replace. With true TDD, a single document fills all of the following roles/needs:

  1. Test (does this work or not?)
  2. Analysis (what are we trying to accomplish?)
  3. Design (how are we going to accomplish it?)
  4. Specification (how will we know when we are done?)
  5. Finish-line (hey, we're done!)
  6. Progress report (hey, are they done, yet?)
  7. Process control (what do I do next?)

...et cetera. It is my opinion that committing to learning TDD - which is a hard discipline and will take a lot of practice to master - requires a clear understanding of the real prize that is at the end of the trail.

Once you've got those things clearly in your mind, you can start worrying about how to do TDD.

The biggest thing I hate in TDD (and also in linux due to the same reasons) that there are too much fanatics (guess who I'm talking about). With such a strict approach any agile methodology can become a nightmare. If you want rules - look at RUP, there you can find about 120 ones. If it's agile methodology - let it be agile. I'm totally against strict rules. Developers should breathe free, that's matters.
Roman
TDD may not be about only writing tests first, however since the development is driven by tests there's a good chance that the tests will come first ...
Duncan
@Duncan: True. @Roman: False.
+4  A: 

"So, though one really believes in TDD, you actually end up going back old style because of time pressure / project deliverables."

Actually, I don't think this can be possibly be true.

If you are "going back old style", the only reason can be because you do not believe that TDD will produce better code more quickly.

I think that someone stops using TDD because they feel it's better produce poor code more quickly.

S.Lott
As Uncle Bob says, *the only way to go fast is to go well*.
Patrick McElhaney
+16  A: 

I find it interesting that none of the responses so far have touched on what I consider to be a fundamental insight into modern development practices, and that is that the "old fashioned" way of writing software by gathering requirements, doing analysis and modelling the desired system before writing any code actually had a lot going for it.

TDD actually embodies this to an extent.

To write a test you first have to know - to put things in very simple terms - what your inputs will be and what your expected outputs will be.

Once you have that knowledge you can write a test to exercise some piece of mythical code and also, to an extent, what other artefacts that code will interact with, before you write that code itself or create those artefacts.

This is what we previously would call "requirements engineering" and "systems analysis" in the old "waterfall" method(s).

Further than that, you will find that once you grasp the requirements at this level, writing tests will come naturally (it is, after all, merely the expression in code of the statement of functionality embodied in those requirements).

And in writing the code that expresses the requirements in the form of tests, you will identify gaps and misunderstandings in the requirements before you've committed those gaps and misunderstandings to the project in the form of executable code.

For modern practitioners of "Agile" methods to admit that they are engaged in a series of "waterfalls" is, I think, too embarrassing, so this need for requirements engineering and understanding is obfuscated behind language that talks around the need to address these things whilst trying desperately to avoid admitting that "Agile" (as commonly understood, or perhaps misunderstood) threw the baby out with much of the bathwater.

Deltics
You had me until the last paragraph. Most agilists don't advocate NO design up front. They just advocate against BIG design up front.
Ben
"as commonly understood, **or perhaps misunderstood**" :)
Deltics
As any hydrologist will tell you, a series of small waterfalls is called a 'rapids'. Thus, if you are engaged in a series of waterfalls, you aren't doing agile, you're doing Rapids Application Development.
Tom Anderson
+3  A: 

Try practicing code kata.

A kata is meant to be memorized. Students of a kata study it as a form, not as a conclusion. It is not the conclusion of the kata that matters, it's the steps that lead to the conclusion. If you want to lean to think the way I think, to design the way I design, then you must learn to react to minutia the way I react. Following this form will help you to do that. As you learn the form, and repeat it, and repeat it, you will condition your mind and body to respond the way I respond to the minute factors that lead to design decisions.

Code kata have given me get a sense of what TDD is supposed to feel like. I know sooner when I'm starting to loose the rhythm, to slip back into old habits. At that point I know I need to take smaller steps, run the tests more often, make sure I'm not trying to refactor under red, etc.

Patrick McElhaney
+6  A: 

So, as far as my case goes, I have written unit tests, but I find myself going to start writing code first instead of writing a test. I feel there's a thought / design / paradigm change which is actually huge. So, though one really believes in TDD, you actually end up going back old style because of time pressure / project deliverables.

You may want to try being absolutely disciplined about TDD for a fixed period - say a couple of weeks or a month. When you catch yourself writing code before tests, delete it and start over, with a failing test. Do this until you know you can, until you know what it feels like - and then you've got the ability to do it, and the freedom to make an informed choice - and understand that it's OK if that choice is sometimes to code first. But don't let habit drive you away from good practices. First get the good practices down and then choose when to apply them (and of course you may find the answer to that is "always", too).

I have few classes where I have pure unit tested code, but I can't seem to continue with the process, when mocks come into picture. Also, I see at times : "isn't it too trivial to write a test for it" syndrome.

Mocks are one thing - are you good at them yet? If you're not comfortable with mocks, and you're in a situation where mocks are appropriate, then practice until - like TDD - you're good with them.

With respect to the "too trivial" issue - not for the first couple of weeks. Just TDD all the time. And when you find that TDD is driving you to a better design - even for "too trivial" code - note it. Think about what your code would look like without it. And you may discover that no code is too trivial to TDD. Or, not. But my point is, try it, seriously, for a significant period, and then you can make better choices. Get comfortable with it, then evaluate.

Carl Manaster
+1. As much as I liked the accepted answer, I like this even more.
Lieven
+1. Same as Lieven. :)
Soe Moe
+1  A: 

Trivial code is where bugs hide. Mainly I think because it's human nature to read what was intended to be there rather than what is there.

I've been trying to discipline myself to follow TDD on all my new projects - it's a hard to break old habits, but I think worth it. It appears to take longer as there is more upfront coding, but debugging time is way down.

Don't think about how you would test the code while you write it. Write tests that exercise how the code should work, then write the simplest thing that makes the tests pass. Lather, rinse, repeat. Your code will probably end up being nothing like you imagined, but will definitely work better.

Also, importantly, write your tests to fail. Writing tests that pass won't help find defects. And this is another very good reason for writing the tests first - if you write the code first, and then the tests, your tests will be written to pass the code, and (unintentionally) biased to test the code rather than the desired result. And how will you know that your tests would fail in the absence of correct code? Since tests are just code, they are susceptible to bugs as well.

So write your test first, then code, bit by bit in parallel. Use the tests to assert that your code is correct, and use the code to assert your tests are correct (yes, it can happen that you are sure your algorithm is perfect, yet the tests are still failing, all because you made a stupid typo in the test. I did it this morning).

Duncan
A: 

When you are in a big mess of legacy code I found Working Effectively with Legacy Code extremely useful. I think improve you motivation for TDD allot even though it is about writing unit tests before you do any changes to your old legacy code. And from the undertone of your question it seems like this is the position you have been.

And of course as many others pointed out discipline. After a while forcing your self you will forgot why you ever did it another way.

Rickard von Essen
A: 

Pair Program doing TDD (Ideally With Someone Better Than You),

Even if it is During Your Free Time

TDD is one of those skills where, at least for me, it's easy to be worse at it than I think I am. My TDD skill always improves when I'm on a TDD project and pair programming with someone who can point out to me when I could be doing TDD better. Even Pair Programming with someone who doesn't know it any better than I do helps me flesh out my ideas better than working alone does.

Find (or start) a Code Retreat or a coding dojo with a specific focus on Pair Programming and TDD.

If your company allows you to, organize one on company time or at least on-site at your company, even if it's only an hour a week, or over lunch.

JeffH
+1  A: 

How do you guys think I should handle this?

I suggest you think your unit tests as dialogs with your object (assuming you are programming with an OO enabled language such as Java, C#, Ruby, PHP, etc..)

Create a test case class, think in your test method about the interaction you want to have with your objects. Imagine you are talking to an intelligent machine using the method you pass to your objects as verbs, and then use Asserts to check the objects have reacted the way you want them to react.

After a while, you might enjoy this style of programmation so much that you would not expect to program without it ;-)

Bernard Notarianni
A: 

My team is trying to get better at following a TDD approach - I have to say that it's not the easiest thing with a larger development team.

Everyone in the team needs to think with their test-first hat on before writing any production code. This can be difficult, as despite what people may say they'll do, there's no guarantee once they get to their keyboard.

For some managers it may appear that TDD is an expensive approach, as I do believe it can take slightly longer to code something (and that is what the bean counters see), but it's short-term "pain" for long-term gain. You then have (hopefully) well written, proven code, with the mechanism in place to pick up errors in the future when things change.

For anyone not convinced, give TDD by example a read and give it a try for an iteration of your software.

Michael
+1  A: 

It's simple:

By learning to think about the "What" __before__ you think about the "How"

In other words, think about exactly what you want to do (interface), rather than you how you are going to do it (implementation)

TDD, as a design tool, based on my experience, really helps you look at things from the user perspective than the coder perspective. In addition, I think TDD helps your mind really thinks about what exactly you are trying to do, what's the expected outcome, etc.

So next time when you are trying out "TDD," ask yourself what it is you are trying to do, and just start writing the code that expresses your intention.

Example:

Say, someone wants you to write them an integer adder.

The person that does not have a TDD mindest will simply just do:

int add(int a, int b)
{
  return a + b;
}

Is the above code correct? Sure it is. But this approach, based on my experience, fails when you have a complicated component to write. (That's why you asked this question in the first place; I know, I had been there before (perhaps still? lol))

The great thing about TDD is that it forces you to give attention first and foremost to the interface (the what) of the system, while not asking you immediately for the implementation (the how).

In other words, if someone asked me to write an adder, I would have something like:

void assertOnePlusTwoEqualThree()
{
  assert( add(1,2) == 3 );
}

Notice, how, even before even thinking about how the add() is supposed to work, I already ironed out a few things. That is, I already figured out:

  • the interface of my adder both inputs and outputs
  • the first trivial test case (unit test for free!!)

then you implement the add().

See, it doesn't matter if the logic discussed here is so simple to implement. To have a TDD mindset, is to apply it all the time with no exception. You have to do it so many times that you don't even think about it anymore. It's just part of how you design. I can say this because I saw it happened to me professionally (it took about a year of perseverance).

Just like how if you always do a good job on programming, regardless of the complexity at hand, you approach your job the same way.

Lastly, I think TDD is comparable to "code sketching." That is, you start trying out to see if the interface works well for each scenario (test case). So it's okay if you end up changing the interface, and the names, etc. See, what I've learned is that a lot of times, design is simply about understanding the problem thoroughly. TDD is one tool that allows you to do that.

Human mind, IMO, works easier with concrete examples (test cases/scenarios) rather than abstract thinking (how to implement something). By having test cases, it allows your mind to gradually learn about the problem you are trying to solve at hand.

It's okay to not know (going back to the "traditional" way...relax, let your mind adjust). It's okay if it's not perfect (writing some implementation code is perfectly okay...your brain is just trying to figure things out). Just keep trying, keep reading, keep coding, but never give up! =)

ShaChris23
A: 

A lot of coding practices take ... practice.

  • You can learn and understand the concept of OO programming in a few hours. But many programmers will admit that it was only after practicing OO programming for about 2 years that they suddenly felt "fluent".

  • A C++ programmer can easily "learn C#" in a matter of days. But it still takes a lot of use before they will be "fluent" and understand the full implications of everything they are writing (rather than being a C++ programmer who converts the syntax to C#).

  • I originally learned to type in the "two fingered" manner. This advanced to the point where I could type pretty fast with this method, but I decided to try to learn touch-typing. For several weeks I forced myself through the pain and frustration of having to type everything really slowly using touch typing. It was hard, and required real commitment because with every line I typed I just wanted to bash it out with the way that I already knew, the way that would give me quick results. But eventually my touch typing speed matched my two-fingered typing.

  • I resisted the MFC prefixing conventions (e.g. "m_" and "p" prefixes) when I first started working with MFC. It seemed ugly, ridiculous and pointless extra typing. Then I forced myself to use this system for a month and after this time I couldn't understand how I had ever written code without this naming convention - it helped me understand the code better and faster, and reduced the number of silly bugs.

So how do you develop the discipline to do TDD? Just commit yourself to doing TDD for a month. It will be slow. It will be hard. It will be tempting to just bash out a few lines "the old way". But after a while you will build up experience and speed, and it will become much easier and more natural to work this way. And then you can evaluate TDD and non-TDD and decide which approach works best. You probably won't look back.

Jason Williams