views:

219

answers:

7

Title says it all (mostly). I'm not sure how "tests first" works and I'd like to hear arguments about when and why one would take this approach.

I hear that it's often recommended to write tests and mock things before writing a single line of implementation. However, I can't help but think that it doesn't fit every situation. For instance, say I'm making a prototype and I'm not sure how everything is going to work yet. So I just start finding examples of each step that I think I need and throwing them into my code. At the end I have a proof of my theory and it didn't take that long. This is essentially "my test". It's not a unit test, but it is a test (most likely it's a console app).

This is pretty much how I work. I think about what I want to do and try to do it. If it works then I eventually go back and write unit tests so that I can trap regression. Is this different than what you're "supposed to do"?

Thank you.

+2  A: 

This is simple, the answer is during prototyping. At this stage you don't understand the system your building well enough to test correctly, and anyways good practice says prototype code should be throw-away code so testing will not give you any real benefits at this stage. But the understanding gleamed from prototyping will help you so you can make effective testing once you enter production.

So yes your approach is correct, if you do test after prototypes

Robert Gould
One could also argue that prototyping is part of the implementation and thus should only happen when you already have some simple API to run basic tests against. That way you first and foremost find out HOW you would like to USE your system, which is one of the advantages with TDD.
Franck
Yes I agree with you, and use this approach too, but I'm talking prototyping at a level beneath API design, such as when you are trying to figure out what types of components and system you need (Because the problem hasn't been solved before or you are trying a radically new approach to something).
Robert Gould
I guess there are indeed some cases where you absolutely need to be able to tweak things easily without the hurdle of early unit testing. I will admit doing this quite often but always feel like I'm lazy not to sit down and think more about my API upfront.
Franck
+5  A: 

The over-arching rule is: Do the riskiest items first.

Doing the test-cases first is, implicitly, arguing that the riskiest part of the coding is miscommunications and misunderstandings of the interfaces and behaviour of the objects that are being created.

For many projects, that may well be true, and TDD is very appropriate in those cases.

However, in many projects that is not the case, and applying TDD in those cases is a poor choice.

If your highest risk is usability, stop futzing about with unit tests and do some UI prototyping.

If your highest risk is performance, do some performance prototypes first, and don't worry about interfaces.

This list goes on.

Doing the risky items first has many advantages:

  • Projects that are inevitably doomed die early, before many resources are wasted.

  • Projects that are in trouble but are salvageable get the project management focus early, when it can do some good.

  • The business side of your organization will value a project higher when it has a low risk of failure; there's less chance that it will be cancelled early unnecessarily.

Oddthinking
A: 

I find that writing tests first does not work so well when I'm still construction the "story" of my code. It is hard to write tests when I'm unsure what the interfaces look like. I might write stub code to flesh out the classes and interfaces without thinking about tests. But I try to get to tests as quick as possible. I find it helps if I make notes of things I would test as I build the design, and then when my design is more solidified I go back to my notes and I make those tests firsts. That usually means the implementation and unit test code grow together, neither one before the other.

ARKBAN
+2  A: 

"I hear that it's often recommended to write tests and mock things before writing a single line of implementation.... I eventually go back and write unit tests... Is this different than what you're "supposed to do"?"

Since you started out with the answer to your own question, then you're not really asking that question are you?

There are lots of reasons why people answer their own questions. Sometimes, it's a way of arguing.
It allows folks to say "I'm not arguing, I'm just asking why this is so wrong".


The goal is test first. Here's how it works.

Say I'm making a prototype and I'm not sure how everything is going to work yet.

I do, however, know one thing. What it's supposed to do.

  1. Write down a concrete example of what it's supposed to do. Concrete, specific inputs and outputs.

  2. That's the test case. I did it first. Can I formalize this as a unit test? Probably not. However, I started with an acceptance test case.

Now, I can break the problem into pieces.

  1. So I just start finding examples of each step that I think I need.

  2. For each example of something I think I need, I write down what goes in and what comes out from the step.

  3. Those are test cases. I did them first. In many cases, I can formalize those as unit tests.

  4. Once I have a test, I go back to the example of each step and throw it into my code.

I did testing, then coding. I didn't do ALL the testing before ANY of the coding. I did testing first, but not in a crazy all-test-no-code way. I did it in an incremental test-a-little-code-a-little way. But everything was test first.

S.Lott
A: 

There is no single 'right way to do it'. However, I do think that Test Driven Development (TDD) would help in your case. I find that writing the tests first helps shape the API and makes the code cleaner. When you write tests first, you are thinking first about how the code will be called (the interface, or the 'what should this do') before thinking about the implementation (the 'how should I do it').

For example, imagine creating a CRM module. You might think that the first thing to do would be to get the customer that spent the most money. So, you would write a test:

Assert.AreEqual(Customer1, crm.GetMostValuableCustomer(), "most valuable customer not as expected");

You might then follow with something like:

Assert.AreEqual(new Customer[] {Customer1, Customer2, Customer3}, crm.GetCustomerByValue(), "GetCustomersByValue() not as expected");

So, the point is that you think about the code from a different perspective (as the consumer, not as the producer). I believe helps me to write much cleaner code, and I don't have to then go back and create regression tests later. I wish I had a better example, but hopefully you can see how working in this method might actually assist you in the prototyping stage.

Travis
+1  A: 

I think your approach of not testing a spike/prototype is just fine. But two ideas:

  1. once you've finished your prototype and you know what you're doing to do, either throw it away and re-implement it test first, or write tests for the code you've already written.

  2. when you've had more practice w/unit tests you might find it faster to create your prototype in a test than create a console app. I don't mean create a tests and a separate class w/the idea, I mean to explore w/code right in the test method. I've done this a number of times and I've been very happy with it. When I'm learning a new api or even a new language the test gives me the fastest feedback cycle for trying an experiment. Then once the code is working I can extract it out into a separate method/class to be part of the real system.

Jeffrey Fredrick
A: 

Even when you are writing a throw away prototype it can still be useful to think in terms of what the prototype will actually do, and start with tests that confirms that it does. Ensuring that the prototype can be tested will also shape the way the solution is approached.

Then when the code is thrown away you still have the tests.

I also have trouble starting with tests for prototypes, but when I have managed to do it I have always been glad I did.

David Sykes