mattvanhorn
Joined 17 years ago
Joined 17 years ago
Personally, I like my tests to be pretty clearly about the behavior of the contract, and not the implementation, which is hard when you require every method have a test.
I'd also be concerned that other team members are reluctant to delete tests - as this is a dysfunction I see often, and try to counteract with varying degrees of success.
But one detail ran counter to my personal practice.
I don't believe that "symmetrical" unit tests are a worthy goal. I believe in testing units of behavior, whether or not they correspond to a method/class. Symmetry leads to brittleness. I refactor as much as possible into private methods, but I leave my tests (mostly) alone. I generally try to have a decent set of acceptance tests, too.
Ideally, you specify a lot of behavior about your public API, but the details are handled in small private methods that are free to change without affecting your tests.
It's true that nothing forces your to refactor - but I think wanting that is a symptom of treating TDD as a kind of recipe-based prescriptive approach. It is not a reflection of the nature of TDD as a practice or habit.
It's a subtle difference, but important:
A recipe says "do step 3 or your end result will be bad"
A practice says "do step 3 so you get better at doing step 3"
But if the design in your head is an algorithm that can be expressed in natural language, then TDD will let you take that and make a loosely coupled, maintainable program out of it.
Good post on the difference here: http://cumulative-hypotheses.org/2011/08/30/tdd-as-if-you-me...
This is why I have to watch co-workers create dozens of useless error classes and utility functions, and totally ignore YAGNI, before actually taking a single step towards a working program.
If you don't know the algorithm, and haven't figured out the abstractions, then just slinging some implementation code is the easiest (and laziest) thing you can do. It's basically a way of avoiding having the necessary conversations. In this case, the question that needed answering before beginning TDD was: "How does one efficiently solve a sudoku puzzle (as opposed to just manipulating one)"
It's no more burden to write step definitions than it is to write RSpec directly. I use SOLID OOP to write my tests, most of the logic lives in regular old methods, and my steps look like:
Then 'the current subscription payment date should be tomorrow' do
verify_next_payment_date(Date.today + 1)
end
Since I start with the Gherkin file, I type less than 10 keystrokes to make the step.