What is test-driven development (TDD)? Is an initial design required?
Asked Answered
F

9

9

I am very new to test-driven development (TDD), not yet started using it. But I know that we have to write tests first and then the actual code to pass the test and refactor it till the design is good.

My concern over TDD is where it fits in our systems development life cycle (SDLC). Suppose I get a requirement of making an order processing system. Now, without having any model or design for this system, how can I start writing tests? Shouldn't we require to define the entities and their attributes to proceed? If not, is it possible to develop a big system without any design?

Fiorenza answered 24/2, 2010 at 15:27 Comment(1)
See uncle Bob's answer to a related question here- #1983830Zeeba
N
9

There is two levels of TDD, ATDD or acceptance test driven development, and normal TDD which is driven by unit tests.

I guess the relationship between TDD and design is influenced by the somewhat "agile" concept that source code IS the design of a software product. A lot of people reinforce this by translating TDD as Test Driven Design rather than development. This makes a lot of sense as TDD should be seen as having a lot more to do with driving the design than testing. Having acceptance and unit tests at the end of it is a nice side effect.

I cannot really say too much about where it fits into your SDLC without knowing more about it, but one nice workflow is:

For every user story:

  1. Write acceptance tests using a tool like FitNesse or Cucumber, this would specify what the desired outputs are for the given inputs, from a perspective that the user understands. This level automates the specifications, or can even replace specification documentation in ideal situations.

  2. Now you will probably have a vague idea of the sort of software design you might need as far as classes / behaviour etc goes.

  3. For each behaviour:

  4. Write a failing test that shows how calling code you would like to use the class.

  5. Implement the behaviour that makes the test pass

  6. Refactor both the test and actual code to reflect good design.

  7. Go onto the next behaviour.

  8. Go onto the next user story.

Of course the whole time you will be thinking of the evolving high level design of the system. Ideally TDD will lead to a flexible design at the lower levels that permits the appropriate high design to evolve as you go rather than trying to guess it at the beginning.

Nannie answered 24/2, 2010 at 15:46 Comment(5)
@Nannie The best answer about TDD i have ever seen. Congratulations. (+1)Inotropic
so what about all the patterns & design principles. While writing test and actual code parallel, how could we identify where to apply what pattern & design principle.Fiorenza
And where does our software product stand, if each developer develop on their style. Most of time, some part is developed by one team and other by another team. It will invite compatibility problem between the components.Fiorenza
@Nirajan Identifying patterns and design principles comes from learning and experience. TDD actually helps naturally avoid a lot of anti-patterns. It is a pretty detailed topic, but books from Robert C. Martin among others are great sources of knowledge on that topic. Working together across seperate teams is also a big topic. Too big to address in this comment, but working in vertical slices of functionality, rather than layers helps. Communication is key to avoiding problems, and the tests you have as a side effect of TDD help identify them quicker.Nannie
Thanks for your great suggestion. Actually, i write few test for demo application. How to decide to which extent we need to refactor the code. As i am new to TDD, is it good practice to use the same in my project, without having enough knowledge on it.Fiorenza
R
6

It should be called Test Driven Design, because that is what it is.

There is no practical reason to separate the design into a specific phase of the project. Design happens all the time. From the initial discussion with the stakeholder, through user story creation, estimation, and then of course during your TDD sessions.

If you want to formalize the design using UML or whatever, that is fine, just keep in mind that the code is the design. Everything else is just an approximation. And remember that You Aren't Gonna Need It (YAGNI) applies to everything, including design documents.

Riffe answered 24/2, 2010 at 15:42 Comment(1)
Great answer. In fact, very similar in spirit to this nice answer.Chrismatory
M
4

Writing test first forces you to think first about the problem domain, and acts as a kind of specification. Then in a 2nd step you move to solution domain and implement the functionality.

TDD works well iteratively:

  1. Define your initial problem domain (can be small, evolutionary prototype)
  2. Implement it
  3. Grow the problem domain (add features, grow the prototype)
  4. Refactor and implement it
  5. Repeat step 3.

Of course you need to have a vague architectural vision upfront (technologies, layers, non-functional requirement, etc.). But the features that bring added-value to your your application can be introduced nicely with TDD.

See related question TDD: good for a starter?

Montespan answered 24/2, 2010 at 15:36 Comment(0)
S
2

With TDD, you don't care much about design. The idea is that you must first learn what you need before you can start with a useful design. The tests make sure that you can easily and reliably change your application when the time comes that you need to decide on your design.

Without TDD, this happens: You make a design (which is probably too complex in some areas plus you forgot to take some important facts into account since you didn't knew about them). Then you start implementing the design. With time, you realize all the shortcomings of your design, so you change it. But changing the design doesn't change your program. Now, you try to change your code to fit the new design. Since the code wasn't written to be changed easily, this will eventually fail, leaving you with two designs (one broken and the other in an unknown state) and code which doesn't fit either.

To start with TDD, turn your requirements into test. To do this, ask "How would I know that this requirement is fulfilled?" When you can answer this question, write a test that implements the answer to this question. This gives you the API which your (to be written) code must adhere to. It's a very simple design but one that a) always works and b) which is flexible (because you can't test unflexible code).

Also starting with the test will turn you into your own customer. Since you try hard to make the test as simple as possible, you will create a simple API that makes the test work.

And over time, you'll learn enough about your problem domain to be able to make a real design. Since you have plenty of tests, you can then change your code to fit the design. Without terminally breaking anything on the way.

That's the theory :-) In practice, you will encounter a couple of problems but it works pretty well. Or rather, it works better than anything else I've encountered so far.

Soni answered 24/2, 2010 at 15:36 Comment(2)
But while giving requirement, customer always ask for estimation for implementation. Is it possible to estimate without design. As we know, writing test and actual code is parallel task, when n how could we do estimation.Fiorenza
You start with talking about the tests: The customer has to help you flesh them out (what needs to be tested, what are the expected results, etc). This will give you a good idea how many tests you need per feature and hence how "big" or complex a feature is.Soni
C
1

Well of course you need a solid functional analysis first, including a domain model, without knowing what you'll have to create in the first place it's impossible to write your unit tests.

Caceres answered 24/2, 2010 at 15:34 Comment(1)
Only you can't do a "solid functional analysis" first since you'd need to know what you'll eventually need for that, i.e. it's predicting the future -> doesn't work. If someone requests a "solid functional analysis", they get "as good as we know right now" and then, they wonder why the design has all these pesky flaws.Soni
B
1

I use a test-driven development to program and I can say from experience it helps create more robust, focussed and simpler code. My recipe for TDD goes something likes this:

  1. Using a unit-test framework (I've written my own) write code as you wish to use it and tests to ensure return values etc. are correct. This ensures you only write the code you're actually going to use. I also add a few more tests to check for edge cases.
  2. Compile - you will get compiler errors!!!
  3. For each error add declarations until you get no compiler errors. This ensures you have the minimum declarations for your code.
  4. Link - you will get linker errors!!!
  5. Write enough implementation code to remove the linker errors.
  6. Run - you unit tests will fail. Write enough code to make the test succeed.

You've finished at this point. You have written the minimum code you need to implement your feature, and you know it is robust because of your tests. You will also be able to detect if you break things in the future. If you find any bugs, add a unit test to test for that bug (you may not have thought of an edge case for example). And you know that if you add more features to your code you won't make it incompatible to existing code that uses your feature.

I love this method. Makes me feel warm and fuzzy inside.

Benedictine answered 24/2, 2010 at 16:32 Comment(0)
M
0

TDD implies that there is some existing design (external interface) to start with. You have to have some kind of design in mind in order to start writing a test. Some people will say that TDD itself requires less detailed design, since the act of writing tests provides feedback to the design process, but these concepts are generally orthogonal.

Maenad answered 24/2, 2010 at 15:36 Comment(0)
S
0

You need some form of specification, rather than a form of design -- design is about how you go about implementing something, specification is about what you're going to implement.

Most common form of specs I've seen used with TDD (and other agile processes) are user stories -- an informal kind of "use case" which tends to be expressed in somewhat stereotyped English sentences like "As a , I can " (the form of user stories is more or less rigid depending on the exact style/process in use).

For example, "As a customer, I can start a new order", "As a customer, I can add an entry to an existing order of mine", and so forth, might be typical if that's what your "order entry" system is about (the user stories would be pretty different if the system wasn't "self-service" for users but rather intended to be used by sales reps entering orders on behalf of users, of course -- without knowing what kind of order-entry system is meant, it's impossible to proceed sensibly, which is why I say you do need some kind of specification about what the system's going to do, though typically not yet a complete idea about how it's going to do it).

Sinatra answered 24/2, 2010 at 15:43 Comment(0)
K
0

Let me share my view:

If you want to build an application, along the way you need to test it e.g check the values of variables you create by code inspection, of quickly drop a button that you can click on and will execute a part of code and pop up a dialog to show the result of the operation etc. on the other hand TDD changes your mindset.

Commonly, you just rely on the development environment like visual studio to detect errors as you code and compile and somewhere in your head, you know the requirement and just coding and testing via button and pop ups or code inspection. this is a Syntax debugging driven development . but when you are doing TDD, is a "semantic debugging driven development " because you write down your thoughts/ goals of your application first by using tests (which and a more dynamic and repeatable version of a white board) which tests the logic (or "semantic") of your application and fails whenever you have a semantic error even if you application passes syntax error (upon compilation).

In practice you may not know or have all the information required to build the application , since TDD kind of forces you to write tests first, you are compelled to ask more questions about the functioning of the application at a very early stage of development rather than building a lot only to find out that a lot of what you have written is not required (or at lets not at the moment). you can really avoid wasting your precious time with TDD (even though it may not feel like that initially)

Kenna answered 3/3, 2013 at 22:30 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.