4 ms·
TDD can be great if you know exactly what you're building and what you must test for, but it gets in the way when you're rapidly prototyping and exploring. It
by onion2k 4y ago
TDD can be great if you know exactly what you're building and what you must test for, but it gets in the way when you're rapidly prototyping and exploring.
It sounds like you're making the mistake of thinking that TDD means writing the tests first. That's not quite right but it's understandable that lots of people believe it given the way TDD is usually discussed.
In TDD you should be writing one test first. Then you write enough code to make that test pass. Then add a second test. Get that to pass. And so on. If you realise you missed something you can delete tests that don't make sense any morejuat like you delete code that doesn't make sense. In essence TDD is about writing the tests in parallel to writing the code instead of writing them afterwards.
You can easily prototype and experiment with TDD because you're never much further ahead with your tests.
TDD is faster than writing tests later because your code has to be testable throughout the process. Writing tests later often means you need to refactor or rebuild to make it testable, which is a waste of effort, even in a prototype.
- rolisz 4y agoBut what test do I write? What does the poorly documented 3rd party API return? Is the test failing because there's an edge case in the API or because my code is wrong?
- sbysb 4y agoThe very first test can be a simple "Did my HTTP request receive a response?". Then you can build on "Does this HTTP response have this value I need".... etc The way I have always gone about TDD is just that I am testing the code I am writing by running the test, not from the main entrypoint of the application. The things you would log and look for when you run the application you instead validate with an `assert()`. Then once you have finished developing, you do a single pass verification from main and you have both a test and a function written
- lcw 4y agoDo you see how playing this game of writing iterative tests would actually provude slower learnings than prototyping a call to an API and receiving a result that would inform a series of tests that would be much more informed? It's just as easy to be inefficient writing useless/bad tests than it is writing bad code. I think every developer should do TDD in their career, because it will make you think about the testability of the code. That said once you understand how to write testable code than I think it makes sense to be flexible on whether you write the test first or take a crack at an implementation. The argument that you should have a good understanding of requirements I think leads to a lot of analysis paralysis, and isn't a practical method for building novel things in a timely manner.
- Jarwain 4y agoI think the key distinction here is "run my new function through the entry point of the application" vs "run my new function from a test". You leave out whatever startup time is involved from the rest of the application to get to that function, & you have a tiny feedback loop to test the function. You have your test which gets the response, and you can still log the output to see what it looks like. It's a little slower at first since you have to write the test, but I'm not sure I see a big distinction vs "have a small script that sends the request".
- atoav 4y ago> Do you see how playing this game of writing iterative tests would actually provude slower learnings than prototyping a call to an API and receiving a result that would inform a series of tests that would be much more informed? And do you see that in many examples just coding ahead without conaidering how to test the code later will in many cases leave you with code that is such a pain to test that you start avoiding the tests because "they take too much time". If you start with the test the question of "how can this be made testable" is unavoidable. I am not dogmatic here. If you are operating on the level of "I am happy if anything works at all" then starting with writing a test is probably a bad idea, better try things out first, scrap the whole thing once you understood what you wanna do in which way and then start writing the tests. For a lot of adhoc code test driven development doesn't make too much sense, but if the stuff you write could ruin someones day (or life) maybe it is the way to go.
- Manfred 4y agoYou start by allowing external requests from inside the test and automate your exploration of the API. Then you slowly evolve it to mock or stub the elements that interact with the external system so you can run your tests in isolation.
- onion2k 4y agoIf you believe the answer to any of those questions is "So I shouldn't write tests, right?" then you must build some very flaky apps.
- maest 4y agoThere is a difference between writing tests once you're done with your exploratory phase and know what you have to code up and doing full blown TDD from the beginning.
- dmitriid 4y agoKent Beck (yes, the Kent Beck): "I get paid for code that works, not for tests, so my philosophy is to test as little as possible to reach a given level of confidence..." https://stackoverflow.com/questions/153234/how-deep-are-your-unit-tests/153565#153565 https://stackoverflow.com/questions/153234/how-deep-are-your...
- onion2k 4y agoI think what Kent is saying there is that he knows which tests he can skip writing because they provide little value. If you're as experienced and knowledgable as Kent then that's probably true. For the rest of us it's better to write too many tests than too few. You might waste some time, but that a smaller problem than accidentally skipping a test that was actually useful and pushed your code in a better direction than you'd have gone without it.
- dmitriid 4y ago> For the rest of us it's better to write too many tests than too few. You might waste some time That's a very bad attitude that is all but enforced by TDD proponents. It's very easy to see which tests are useless and which are not. So you end up with people writing thousands of unit tests and little-to-no integration or functional tests because: - "TDD told me so", and - Testing frameworks are written by people who adhere to the same philosophy Whereas there's very little utility in those "too many tests" while they give you a very false sense of security.
- onion2k 4y agoIt's very easy to see which tests are useless and which are not. For trivial things, maybe, but then people start applying the 'rule' to non-trivial things "because it's easy" and they get it wrong. All I'm saying is that until you are a Kent Beck level expert it's safer to err on the side of caution. When you have a ton of experience and knowledge you can do what you like. Also note that I said its better to write too many tests than too few - that still doesn't mean you should test everything, or that you have to test trivial things. It just means when you're not 100% sure it's safer to write a test.
- heretoo 4y ago> It sounds like you're making the mistake of thinking that TDD means writing the tests first. Actually, Kent Beck, who coined the term TDD, has the following to say in his book "Test Driven Development": "In Test-Driven Development, we Write new code only if an automated test has failed" This implies that in TDD the test is written first. Regardless of any definition, test-first and test-last are just two ends of a scale we can use.
- erik_seaberg 4y agoHe’s saying to write a test before its code, but don’t write all the tests before any code.
- dmitriid 4y agoHe's also saying "I get paid for code that works, not for tests, so my philosophy is to test as little as possible to reach a given level of confidence..." https://stackoverflow.com/questions/153234/how-deep-are-your-unit-tests/153565#153565 https://stackoverflow.com/questions/153234/how-deep-are-your...
- dgb23 4y agoI have to disagree with that last statement. The code I write initially can often be very dumb, repetitive and procedural. I often have to discover and see what the data structures really look like, what the public API looks like, what I leave in code and what I want to be data driven etc. At this stage it makes little to no sense to write tests first. All I need is to see the output, which might change dramatically during development. It’s a very fast, direct way of programming, with a lot of copy pasting and long parameter lists. When the code is laid out like that, then I can see where it’s going. I see the repetitions, the edge cases etc. Now it starts to make sense to design the data structures, give declarative names, find the right abstractions. Now I can move forward with tests.
- mettamage 4y agoThat first phase is what I call “playing around”. A necessary phase. When you explore/play one shouldn’t test because one is learning. Testing (aka evaluation) should happen when one knows the routine + outcome you want to evaluate that routine one. Whether it’s code or improving your singing or learning in school. This generalizes to all of that, IMO
- pydry 4y ago>The code I write initially can often be very dumb, repetitive and procedural. I often have to discover and see what the data structures really look like, what the public API looks like, what I leave in code and what I want to be data driven etc. I do this plenty after writing a new (high level integration) test. Usually I have a fairly clear idea of what the public API I want should look like before I code. A test that calls that API makes a good test. I might tweak the way it is called when coding the implementation, but probably not by much. Underneath it the integration test doesn't care what kind of data structures you use and it provides a safety harness to let you discover at will. >At this stage it makes little to no sense to write tests first. All I need is to see the output, which might change dramatically during development. I frequently write the test first for this type of code - e.g. APIs that output JSON blobs or command line apps that output a wall of text. Where I'm expecting the output to change I program the test to temporarily overwrite it with the results of the program, eyeball the result and commit it all together if it's correct.