Comments by "" (@grokitall) on "TDD Is A BROKEN Practice" video.
-
Your comment demonstrates some of the reasons people don't get tdd.
First, you are equating the module in your code as a unit, and then equating the module test suite as the unit test, and then positing that you have to write the entire test suite before you write the code.
This just is not how modern testing defines a unit test.
An example of a modern unit test would be a simple test that when given the number to enter into the cell perform a check to see if the number is between 1 and the product of the grid sizes and returns a true or false value.
For example your common sudoku uses a 3 x 3 grid, requiring that the number be less than or equal to 9, so it would take the grid parameters, cache the product, check the value was between 1 and 9, and return true or false based on the result. This would all be hidden behind an API, and you would test that given a valid number it would return true.
You would then run the test, and prove that it fails. A large number of tests written after the fact can pass not only when you run the test, but also then you either invert the condition, or comment out the code which supplies the result.
You would then write the first simple code that provided the correct result, run the test, see it pass, and then you have validated your regression test in both the passing and failing mode, giving you an executable specification of the code covered by that test.
You would also have a piece of code which implements that specification, and also a documented example of how to call that module and what it's parameters are for use when writing the documentation.
Assuming that it was not your first line of code you would then look to see if the code could be generalized, and if it could you would then refactor the code, which is now easier to do because it already has the regression tests for the implemented code.
You would then add another unit test, which might check that the number you want to add isn't already used in a different position, and go through the same routine again, and then another bit of test and another bit of code, all the while growing your test suite until you have covered the whole module.
This is where test first wins, by rapidly producing the test suite, and the code it tests, and making sure that the next change doesn't break something you have already written. This does require you to write the tests first, which some people regard as slowing you down, but if you want to know that your code works before you give it to someone else, you either have to take the risk that it is full of bugs, or you have to write the tests anyway for continuous integration, so doing it first does not actually cost you anything.
It does however gain you a lot.
First, you know your tests will fail.
Second you know that when the code is right they will pass.
third, you can use your tests as examples when you write your documentation.
fourth, you know that the code you wrote is testable, as you already tested it.
fifth, you can now easily refactor, as the code you wrote is covered by tests.
sixth, it discourages the use of various anti patterns which produce hard to test code.
there are other positives, like making debugging fairly easy, but you get my point.
as your codebase gets bigger and more complex, or your problem domain gets less well understood initially, the advantages rapidly expand, while the disadvantages largely evaporate.
the test suite is needed for ci and refactoring, and the refactoring step is needed to handle technical debt.
8
-
2
-
2
-
That one is actually quite easy to answer if you look at how GUI code has been historically developed.
First, you write too much of the UI which does nothing.
Second, you write some code which does something but you embed it in the UI code.
Third, you don't do any testing.
Fourth, due to the lack of testing, you don't do any refactoring.
Fifth, you eventually throw the whole mess over the wall to the q & a department, who moan that it is an untestable piece of garbage.
Sixth, you don't require the original author to fix up this mess before allowing it to be used.
When you eventually decide that you need to start doing continuous integration, they then have no experience of how to write good code how to test it, or why it matters. So they fight back against it.
Unfortunately for them, professional programmers working for big companies need continuous integration, so they then need to learn how to do unit testing to develope regression tests, or they will risk being unproductive and risk being fired.
1
-
1
-
1
-
1
-
@Storytelless first, you separate out the code that does the search, as it is not part of the ui, and write tests for it.
Then you have some ideas as to what parameters you want to pass to the search, which are also not part of the ui, and add tests for those.
Finally, you know what those parameters are going to be, which hints at the ui, but you have the ui build the search query, and test that that query is valid.
Only after all of this is it necessary to finalise the shape of the ui, which is a lot easier to test due to all of the other stuff you have already removed.
The ui should be a thin shim at the edge of the code which just interacts with the user to get the parameters. This was it is easier to replace it with a different one if your ui design changes, because you have already removed all of the other stuff which is ui dependent.
You can then test the ui using one of the guides test frameworks, just looking to see if the automated step you have recorded actually selects what you expected it to and returns the correct value.
1
-
1
-
1
-
1
-
1
-
@evgenyamorozov no, it won't compile, but you are designing the public api, so it does not need to. Once you have an api call which is good enough, you have your failing test, which fails by not compiling, so you create a function definition which meets that api, and a minimal implementation which returns whatever value your test requires, thereby compiling and passing the test.
Then you come up with another example which returns a different result, which then fails, and make just enough changes to the implementation to pass both tests. Then keep doing the same thing.
1
-
1
-
1
-
1
-
1
-
1
-
1