3 ms·
I will start doing TDD all the time when: 1. It is faster than developing without it. 2. It doesn't result in a ton of brittle tests that can't survive an upg
by hakaaaaak 14y ago
I will start doing TDD all the time when:
1. It is faster than developing without it.
2. It doesn't result in a ton of brittle tests that can't survive an upgrade or massive change in the API that is already enough trouble to manage on the implementation-side- even though there may be no functional changes!
Some other thoughts:
Unit tests that test trivial methods are evil because the LOC count goes up (maintenance anyone?) and the number of entry points and NPE possibilities or checks goes up (bugs anyone?) -> TDD promotes testing trivial methods -> TDD promotes evil
TDD increases the chance that more people will mock, and mocking can lead to brittle tests -> TDD increases the chance many of these brittle tests will be written -> Lots of brittle tests means that you throw them away later or rewrite the whole app (with more tests!)
TDD promotes 100% test coverage of the code you write -> Very, very few successful companies have 100% test coverage -> Code with 100% test coverage has brittle tests (period) -> TDD promotes things that are not best-of-breed practices in a quest for the false god of 100% test coverage.
I was a firm believer in what Kent Beck, Ron Jeffries, et al were pushing in the early part of the last decade. But since then I think most of the rest of the world already knows that TDD practiced religiously will lead to huge amounts of code that slow... down... development... and... make... it... easier... to... buffer... estimates... because when absolutely required you can stop TDD and just hack a spike into production. And... when the application needs to be rewritten because it is too crazy complicated to change all of those tests- you just rewrite it, and we all love greenfield development!
- cheald 14y agoThis is a big part of the reason that I like BDD over unit-oriented TDD. BDD saves you time overall (once you've gotten over the initial hump), and tends to result in high-level tests that survive a major restructuring of internals. In such a system, mocks (with perhaps the exception of external resource mocks) are usually an indicator that you need to refactor something. That said, I think that unit tests still have their place - you just have to be careful to not test implementation as much as input/output.
- boyter 14y ago1. It can be. For something like a standard C# MVC application (Im working on one now) the time taken to spin up Casini or deploy to IIS is far greater then running tests. For something like PHP where you are just hitting F5 and TDD can slow you down. As with most things it depends. 2. If you are writing brittle tests you are doing it wrong. Increasing LOC isn't always a bad thing. If those increased LOC improve quality then I consider it a worthwhile. Yes it can be more maintenance, but we know the cost of catching bugs in development is much cheaper then in production. Mocking isn't as bad as its been made out to be. Yes you can overmock things (a design anti-pattern), but that should be a sign of code smell and you should be re-factoring to make it simpler. If you cant re-factor and you cant easily mock then consider if you really need to test it. In my experience things that are hard to mock and cannot be re-factored usually shouldn't be tested. Exception being legacy code, but we are talking about TDD here which usually means greenfield development or else it would have tests already. Unit testing does NOT promote 100% coverage. People using unit tests as a measure promote this. Sometimes its worth achieving, and sometimes its not. Use common sense when picking a unit test coverage metric. I have written applications with close to 100% coverage such as web-services and been thankful for it when something breaks and I needed to fix it. I have also written applications with no more then 20% over the critical methods (simple CRUD screens). Use common sense, testing simple getters and setters is probably a waste of time so don't do it. Unit testing isn't all about writing tests. Its also about enforcing good design. Code that's easily testable is usually good code. You don't have to have tests to have testable code, but if you are going to that effort anyway why not add where they can add value and provide you with a nice safety harness? Most of the issues with unit tests come with people preaching that they are a silver bullet. For specific cases they can provide great value and increase development speed. Personally I will continue to write unit tests, but only where my experience leads me to believe they will provide value.
- andrewflnr 14y agoRe 1, GP is talking about time to develop features, including writing tests, not to actually run the tests.
- Glide 14y ago
- pufuwozu 14y agoTDD increases the chance that more people will mock Absolutely false. Try TDD in Haskell. Know how many mocking libraries there are in Haskell? None. Totally unnecessary.
- hakaaaaak 14y agoI should have considered Haskell. :) In other languages, it is true, so it isn't absolutely false.
- corey 14y ago> TDD promotes testing trivial methods Kent Beck might disagree: http://stackoverflow.com/a/153565 http://stackoverflow.com/a/153565
- hakaaaaak 14y ago:) Kent Beck doesn't promote it anymore, but in the early 2000's that was what was understood. From "Test Driven Development" by Kent Beck, published 2002: http://www.amazon.com/Test-Driven-Development-Kent-Beck/dp/0321146530 http://www.amazon.com/Test-Driven-Development-Kent-Beck/dp/0... Here are some excerpts: "What test do we need first? Looking at the list, the first test looks complicated. Start small or not at all. Multiplication, how hard could that be? We'll work on that one first." The examples like this that were provided were of trivial methods. Trivial can be subjective, but, to me, methods whose bodies are almost always 2-5 lines long, not counting calls to other trivial methods, which may account for maybe another 2-3 additional lines, are basically trivial. It's one thing when you really don't need that much code, but it's another when you have classes upon classes upon classes upon classes, etc. to do something that could be OO and be in two classes with 1/2 as many lines and still be clear. "Do these steps seem small to you? Remember TDD is not about taking teeny-tiny steps, it's about being able to take teeny-tiny steps. Would I code day-to-day with steps this small? No. But when things get the least bit wierd, I'm glad I can." This is what Kent meant, but few of us picked up on it, per the first comment to his answer in your example from S.O. and per my experience. I'm not blaming Kent, Ron, etc. or even saying that they are or were wrong. But, the commonly understood epitome of TDD used to be 100% test coverage and methods for just about everything. Those in the know said more like 60% was better overall but that was not really "true TDD". The implication of 100% "trivial" methods is more overhead for method calls (minor cost, depending, but can be cumulative, increase/decrease call stack size more quickly, which is inefficient), a large number of entry points (more stuff can be null/nil, cause NPE's or need checks if you don't know what is going to call it later, though that can be mitigated somewhat), and just generally too many LOC.
- nahname 14y ago1. It is only fast if you are working solo on a project for less than 2 months. Each extra person, subtract two weeks. Think larger scale than just adding a feature. You always have to refactor to add the next feature. The giant mess you created takes time to understand and change. With tests, your abstractions actually work. Focus on what you need to change, change it, fix the failing tests, repeat. 2. If having tests during a major refactoring/redesign slows you down, you are writing the wrong kinds of tests. Changing code should break your tests. Not all of them, but the ones where you have changed the behavior. Unit tests are more valuable than integration (rails controller tests) tests which are more valuable than functional tests (browser/request). If all you have are the later, they will break for everything and provide little feedback as to the cause. More general tips. Test logical switches, not assignments. If you have to deal with lots of mocking, try to avoid state mutation and use a more functional approach. Mocking is a result of interaction testing. Code coverage only tells you if you are lacking in quality, not that quality is present. 100% doesn't mean you have good tests. Test what matters, don't test everything. I realize your argument is for using TDD all the time. The problem is that your complaints are from the standpoint of, I never want to test anything. There are very valid reasons for not using TDD all the time. You just haven't listed any.
- hakaaaaak 14y ago> 100% doesn't mean you have good tests That's true, but if you are really doing TDD the way some understand it (small methods, readily testable), then 100% test complete TDD means you didn't write any code you didn't test intentionally. By 100% coverage, I don't mean a code metric result from a tool, I mean that you followed TDD to a T and didn't write code that you didn't test carefully and intentionally. The loose form of TDD you mention is not TDD by others' standards. Strict TDD never says, "those tests you wrote to test the app in the browser- those are enough; you don't need to unit test that, because you're testing all the important and edge cases we care about, even without unit tests." Yet, that may result in fewer, less brittle tests that can survive an upgrade or other massive changes in the implementation.