Is the real benefit in TDD the actual testing of the application, or the benefits that writing a testable application brings to the table? I ask because I feel too often the conversation revolves so much around testing, and not the total benefits package.
TDD helps you design your software. The tests becomes the design. By writing the test first you think about your code from a consumer perspective, making a more user friendly and more compact software design.
Also, by applying TDD you typically end up writing your code in a way where you can supply test mocks and stubs. This leads to less coupled software, making it easier to change and maintain over time.
So I guess allot of the talk around TDD is about testing, but by doing that other big benefits follow, such as quality (coverage), flexibility (decoupling), better design (think as the consumer of the API).
The real improvement is that it is a good way to force you to really think through the design and implementation. Then, once you've prepared the tests and written the code, solutions to unforeseen problems appear more easily.
Something that usually happens to me that is a good analogy: When I'm going to post a question to a forum or IRC channel, I like to have the problems well written and fully described, many times the process of preparing a well written and complete description of the problem magically makes the solution appear.
The real benefit of TDD is supposed to be that it allows you to modify/refactor/enhance your application without worrying about whether you've broken existing functionality. The fact that writing unit tests tends to result in loosely coupled code and better architecture isn't necessarily the point of TDD, but I think it's hard to have one without the other.
You can't really experience the benefit of TDD unless you have unit tests with good coverage. In order to do that, you're going to have to write testable code. That's why the two are often used in conjunction or in place of one another.
Automated testing is such a time saver and confidence booster when you are developing a product that you'll ship multiple versions of. With automated tests, you know that you haven't broken anything between versions. This especially helpful when your product is something that people can write add-ons for - you don't want to break their add-ons between versions.
With TDD, you get a good suite of tests as you develop. Without TDD writing those tests is much more difficult.
Michael Feathers has an insightful blog post about this titled The Flawed Theory Behind Unit Testing. Seriously, go read it. The punch line is
All of these techniques have been shown to increase quality. And, if we look closely we can see why: all of them force us to reflect on our code.
but you should read the full post for the context.
Automated testing keeps humans from doing a machine's job.
Test-driven development maximizes the amount of automated testing.
Beyond a certain point, of course, a human is still required. You reach diminishing returns when you try to apply TDD beyond that point.
Related
Chapter about TDD from Martin's "Clean Code" caught my imagination.
However.
These days I am mostly expanding or fixing large existing apps.
TDD, on the other hand, seems to only be working only for writing from scratch.
Talking about these large existing apps:
1. they were not writted with TDD (of course).
2. I cannot rewrite them.
3. writing comprehensive TDD-style tests for them is out of question in the timeframe.
I have not seen any mention of TDD "bootstrap" into large monolite existing app.
The problem is that most classes of these apps, in principle, work only inside the app.
They are not separable. They are not generic. Just to fire them up, you need half of the whole app, at least. Everything is connected to everything.
So, where is the bootstrap ?
Or there is alternative technique with results of TDD
that'd work for expanding the existing apps that were not developed with TDD ?
The bootstrap is to isolate the area you're working on and add tests for behavior you want to preserve and behavior you want to add. The hard part of course is making it possible, as untested code tends to be tangled together in ways that make it difficult to isolate an area of code to make it testable.
Buy Working Effectively with Legacy Code, which gives plenty of guidance on how to do exactly what you're aiming for.
You might also want to look at the answers to this related question, Adding unit tests to legacy code.
Start small. Grab a section of code that can reasonably be extracted and made into a testable class, and do it. If the application is riddled with so many hard dependencies and terrifying spaghetti logic that you can't possibly refactor without fear of breaking something, start by making a bunch of integration tests, just so you can confirm proper behavior before/after you start messing around with it.
Your existing application sounds as if it suffers from tight coupling and a large amount of technical debt. In cases such as these you can spend a LOT of time trying to write comprehensive unit tests where time may be better spent doing major refactoring, specifically promoting loose coupling.
In other cases investing time and effort into unit testing with Mocking frameworks can be beneficial as it helps decouple the application for purposes of testing, making it possible to test single components. Dependency Injection techniques can be used in conjunction with mocking to help make this happen as well.
I a bit familiar with rspec [Ruby] and specs [Scala]. Yesturday I passed a tutor for Cucumber. What I disliked about Cucumber is that additionally to describing scenarios (like you would do with spec- or xUnit-style testing) you have to implement extra layer of indirection: translating scenario steps into ruby expressions. For me creating unnecessary (?) extra layers of indirection feels like "heavy-weight" J2EE-way, not like "light-weight" ruby way. Is understandability by "domain experts" the only advantage of Cucumber? Or is there some non-obvious (technical?) advantages for developer/tester as well?
BDD, from a practical standpoint, is highly synonymous with TDD. Rspec is a BDD test framework, as well as Cucumber.
That stakeholders can read and understand Cucumber acceptance specifications is certainly a key advantage, but this fact alone really doesn't get at the real benefit of Cucumber. Your features and scenarios ought to grow somewhat in specificity as the work being done for them moves through the value stream of your team's development cycle.
Some teams may have an analyst scoping out work at the beginning of the cycle. Sometimes this analyst writes gherkin acceptance specifications, but whoever writes the first draft, you would expect them to be fairly coarse grained. They may not cover every un-happy path.
As the developers take up the work, they often discover edge cases and missing scenarios. At this point they can touch base with the analyst, and the results of such conversations should be written into the cucumber features.
In my experience the testers have cultivated an even more critical eye, and thus it is not uncommon to see them add even more scenarios and features. The testers may also uncover defects, which should be added to the cukes to protect us from regression.
The point is that, in addition to providing executable documentation for our code, Cucumber also provides a repository for the state of the team's conversations vis a vis the features being developed.
There is certainly extra overhead to all of this. However, it's worth considering how much overhead is already in your team's process, which Cucumber might serve to streamline. I find that Cucumber helps reduce the amount of thrash that happens in communication about features both within and outside of the team room.
I should also mention that cucumber is intended as full-stack acceptance testing, and therefore should be less fine-grained, relative to your unit tests. And cucumber is not a good substitute for unit and integration tests. I also would never recommend using cucumber to verify aesthetic aspects of your app's UI. Just use it to validate the actions which a user might take when using your app.
Cucumber is designed to help engage business stakeholders in refining developers' and testers' understanding of the system by collaborating to create scenarios that everyone can understand.
The act of engaging business stakeholders pays off because everyone gets a better understanding, they start sharing the same language and carrying that language into the code (see Domain Driven Design's "Ubiquitous Language"), which can lead to better estimates, appreciation of scope, conversations around options for achieving the same goal, etc. etc.
There are certainly other ways of achieving the goals. For instance, on our C# project we talk through the scenarios, write them on a wiki then implement them using a little custom Domain Specific Language rather like this one. The same thing could be done in Ruby.
BDD is the process of learning the places where we thought we knew what we were doing, but it turned out we were wrong - the discovery of ignorance. With Feature Injection and unit-level examples, this happens at multiple levels of granularity, all the way up to the project vision itself. It tends to pay back for itself, but you don't need a BDD framework to do BDD.
The conversations in BDD are the important bits, not the tool you use to capture them (I helped write JBehave and still believe this is true). Automating regression tests is also important to cut down the manual effort which rises as the codebase grows, and Cucumber, DSLs and other BDD tools give you this as a very nice by-product which also help you trace, and drive out, the shared understanding.
Edit: I should mention that the reuse of steps is also important, but it doesn't make much difference whether you use a BDD framework or a DSL for that. It does make the difference between a DSL and just procedurally mimicking every user interaction.
It depends what you want to achieve.
Cucumber adds overhead, can be tricky to get used to, takes time to master.
If you want your domain experts to be able to read your tests, you should definitely give it a try.
On the other hand, if developers are the only people reading your tests, you can probably stick to rspec/unit-test/etc. and write your integration tests in those frameworks. However you might achieve more readable high level documentation by using cucumber.
See for example rspec 2 core features' descriptions in cucumber.
My question is same as the title. I have not done Test driven development yet,I have performed unit testing and I am aware of testing in general but I hear it is much advantageous to follow TDD?. So should I opt for it everytime or are there some preconditions... i just need to know some basic or important requirements when i should opt for TDD. Sorry if this question is too trivial.
I would say whenever you are coding for a project. By this I mean where you are hoping to produce code that will be used by people. This is basically all code apart from research where you are learning and discovering new techniques.
Even if you think the project is just a small one often things spiral up out of control without care. You wil be glad for the tests when you find yourself having to refactor a big sprawl of code.
Also note that tdd isn't just about testing. It is a methodology of development that encourages you to create clean and solid designs.
As you are starting out tdd everything. Once you have more experience then perhaps you can back off and determine when to not tdd.
IMHO if you are not comfortable with TDD, trying to apply it in projects where you will need to interact/use legacy code it's much more complex than applying it in a project from scratch. In fact, there is a whole book about this.
HTH
My advice would be to use unit testing as often as possible.
Caveat: In my experience TDD works best when working with technologies you already have some experience with. It's often hard to write test assertions if you do not know exactly what the desired result looks like (For example, try writing the test for an ASP.NET MVC action method if you never wrote an action method in your entire life). In those cases you're probably better off writing unit tests after implementing the code.
If I am developing something without a user interface, I always use TDD these days. After all, you have to test the software. You can either do the extra work and do TDD, or you can do the extra work and cludge together a user client just for testing. The former tests more completely and in a more repeatable fashion.
Doing TDD against user interface code, on the other hand, hasn't really delivered much value for me. For various business reasons I'm restricted to Visual Studio out of the box for my work, and "recording" tests with VS is a huge time sink, especially when you have to re-record them if you change the UI. I do TDD for the business logic behind the UI, but not the UI itself.
Closed. This question is off-topic. It is not currently accepting answers.
Want to improve this question? Update the question so it's on-topic for Stack Overflow.
Closed 10 years ago.
Improve this question
I've been using TDD for server-side development. I'm not really sure if the benefits of having all of my production code surrounded by unit tests outweigh the disadvantage of spending 4x more time than needed on refactoring.
But when I'm developing UI code, I simply cannot apply TDD. To all fundamentalists out there, the first law of TDD states that "you may not write production code until you have written a failing unit test". But how can this be if you are developing UIs?
(One can use acceptance test frameworks like Selenium, but that doesn't count, because you don't interact directly with the source code.)
So, can I tell my manager that because of the new >90% code coverage policy I cannot write user interface code?
If you find that writing TDD causes you to spend 4x more time on refactoring, you need to be writing better, more isolated tests, and really let the tests drive the design, as intended. You are also not counting the time you spend in the debugger when you refactor without tests, not to mention how much time everyone else spends on bugs you introduce when you refactor.
Anyway, here is some good advice about what TDD means for UI development. How much that will translate into code coverage depends heavily on the UI framework.
Definitely don't tell your manager you can't do it, he may just replace you with someone who can.
First off, even Robert Martin has testing challenges with UIs.
When TDDing a UI, you write "behavioral contracts" that get as close to the action as possible. Ideally that means unit tests. But some UI frameworks make that inordinately difficult, requiring that you step back and use integration or "acceptance" tests to capture how you expect the UI to behave.
Does it not count if you can't use unit tests? That depends on which rules you're using to keep score. The "only unit tests count" rule is a good one for beginners to try to live with, in the same vein as "don't split infinitives" or "avoid the passive voice". Eventually, you learn where the boundaries of that rule are. In one podcast, Kent Beck talks about using combinations of unit and integration tests, as appropriate (adding, if I recall correctly, that it doesn't bother him).
And if TDD is your goal, you can most certainly write Selenium tests first, though that can be a slow way to proceed. I've worked on several projects that have used Selenium RC to great effect (and great pain, because the tests run so slowly).
Whatever your framework, you can Google around for TDD tips from people who've fought the same battles.
TDD is about testing methods in isolation. If you want to test your UI you are doing integration tests and not unit tests. So if you carefully separate the concerns in your application you will be able to successfully apply TDD to ANY kind of project.
That policy sounds a little artificial, but I would agree with the answer that UIs require functional test cases, not unit test. I disagree however with the point about which comes first. I've worked in an environment where the UI functional tests had to be written before the UI was developed and found it to work extremely well. Of course, this assumes that you do some design work up front too. As long as the test case author and the developer agree on the design it's possible for someone to write the test cases before you start coding; then your code has to make all the test cases pass. Same basic principle but it doesn't follow the law to the letter.
Unit tests are inappropriate for UI code. Functional tests are used to test the UI, but you cannot feasibly write those first. You should check with your manager to see if the >90% code coverage policy covers UI code as well. If it does, he should probably seriously rethink that move.
Separate the business logic from the UI and ensure that the UI code takes less than 10% of the total? Separation of concerns is the main goal of TDD, so that's actually a good thing.
As far as 90% coverage goes ... well, best course is to review extant literature (I'd focus on Kent Beck and Bob Martin), and I think you'll find support for not following a mindless coverage percentage (in fact, I think Uncle Bob wrote a blog post on this recently).
A having a >90% code coverage is dumb because a smart dev can get 100% coverage in one test. ;)
If you are using WPF, you can test your UI code if you use the MVVM pattern. By test your UI code, i mean you can test the ModleView but there is nothing that I know that can test XAML.
Read Phlip's book
I would really love to push for TDD development inside the shop I'm working in. Lots of the seniors over there didn't work with unit testing or did unit testing that was hitting the database.
I would love to bring some good arguments, books for training, possible coach to ease the transition.
I have found that it is often very hard to push TDD from the developer up. What I tend to do is talk about the benefits of TDD as much as possible and wherever possible, introduce elements of TDD myself bit by bit.
If they don't mind, start a new project with unit tests in it (managers seldom mind more test coverage) and start developing that way yourself. Slowly show the rest of your team the benefits and try to win some converts. Once you have a few other developers on your side, start pushing management for some training.
You could also offer to run some lunch-n-learns about it for the other developers. Teaching is the best way of learning and your will hopefully gain allies. If you are lucky, you can talk your boss into buying the pizza for the lunch-n-learn and everyone benefits.
Like Rob P said - I also found that preaching ended me with a hoarse voice and no one listening. I got results faster and more widespread by doing it and keeping that part visible. Be open to questioning and don't force it. Encourage and praise but don't preach.
Combine it with publishing the results of your testing- and have that automated - you can send out an email perhaps. You want many subtle reminders to show people how good your method is.
I think a good way to sneak in TDD principals into an existing product is to start writing unit tests for bugs. This way you slowly start to build up a set of unit tests for regression testing which become an integral part of the project, especially if you can get them run as part of your build process.
The only hurdle will be the existing code might be resistant to testing, but that's just another excuse to do some refactoring.
Once people start to realise the benefits the momentum will grow, but you need to pioneer the way.
While I can't tell you what will work, I can tell you some things that definitely will not work and should be avoided:
I'll write the code, you write the test
This always comes up at first. People assume that since you're so gung-ho about testing, you should be the one writing the tests. This doesn't work at all and misses the whole point.
You wrote the test that's breaking, so you have to fix it.
If you start writing tests for your code, inevitably someone else will break those tests. Then, if you ask them to fix it, they'll often say it's your responsibility. This isn't necessarily them being a jerk, it could just be that they don't understand the process. This is where you'll need management backup.
I'll just start, and everyone will follow.
Like others have said, TDD without management support is very hard. If there are any devs who don't "drink the Cool-Aid" then they will constantly be breaking your tests and not caring. If you can't make them believe, then you need management telling them it's their job.
What finally brought me around was watching a project collapse due to too many bugs. It convinced me that I was doing something fundamentally wrong. A little research brought me to automated testing, and with a little determination I taught myself the basics. Perhaps talking to your fellow devs about similar projects (we all have at least one...) will help them realize that they might want to try something new.
Lead by example:
use TDD on all the code you write
show them the benefits as soon as you have the opportunity (regression detected by the unit test or incident recreated in your unit testing environment)
deliver "clean code that works"
propose your assistance to others
don't be dogmatic - TDD is not silver bullet
make your unit tests visible: they should compile along with the code they test
If the project doesn't have enough unit tests, you can point out bugs in the issue database that would probably have been avoided if there had been unit tests.
As for pushing TDD, or some other code religion, don't bother.
For some people (and some types of code), TDD is great. Some people don't work that way, and don't benefit from test-first. As long as they don't avoid testing altogether, I don't think it matters.
A great challenge with TDD that is brought in "bottom up" is that, when push comes to shove (as it inevitably does when a deadline approaches), management is going to over-ride the emphasis on tests: "We can't afford to test! We have to finish the project!"
Of course, this is the very situation (deadline looming, significant backlog, progress not on track with promises, leading to rapidly shifting priorities and tasks) where the benefits of TDD really kick in. Management over-rides it, the project / iteration starts to come apart in the same-old same-old, and management looks back and says "We tried TDD and it didn't help at all."