I'm trying to understand, or "get on board" the TDD (or even just hardcore testing, TDD or not) bandwagon, but my brain is resisting.
It seems logical to me that one difference between a fully testable implementation and one that is not, is that the non-fully-testable one would (or could) have larger blocks of code, where logically relevant portions are physically together, whereas, the fully-testable one would have to break up these larger chunks into smaller methods such that each piece can be individually tested, so in the event of refactoring, your tests can tell you not only that there is a problem, but precisely where that problem is.
Can someone comment on whether this is true or not?
And if this is true, would there not be at least some costs (support & "readability", at least) associated with that?
I would half agree. A fully testable implementation being broken up into blocks that are testable is pretty much a truism. In order to construct software that is testable it must be done in a particular way. So the granularity of testing forces the size of testable modules of a system.
However, it's not about logically relevant or longer blocks of code. It is more about coupling. In untestable code the coupling is usually high, one cannot modify one part of the system without affecting another. I believe that this is why programming to an interface rather than an implementation is a very important concept.
So let's imagine a look at the "extreme" end of the spectrum of TDD with unit tests where they practice ping pong pair programming (programmers trade off writing tests and passing them) the code will likely look different. The "testable unit" is now not only the size of a unit test (constrained to a single class in OOP languages), but the ping pong aspect ensures that these code would be added in a time limit between tests (just try hogging the keyboard for half a day!). This doesn't mean that methods won't become long, it just means that the human constraints around the problem will force it to become a certain size.
There are some costs, but usually smaller classes are far easier to understand and maintain. After making a codebase testable you'll usually find that the code goes from procedural to object oriented.
I think this is partially true. But I think it goes beyond breaking your code down into smaller modules.
To me, the biggest difference between testable and non-testable code is decoupling code from dependencies through interfaces (vs. class coupling), and then being able to mock those dependencies.
Even if your code is in small, independent chunks, it's still not testable if it has tight class coupling.
To a certain extent TDD drives you towards smaller classes and methods, yes. But I'd call that a good thing - readability goes way down as soon as a class is doesn't fit on a single screen.
(And if you're starting with a big class, just drawing lines and cutting it into smaller chunks won't get you something testable. You have to keep related pieces together and split unrelated pieces apart, i.e. separation of concerns)
It seems logical to me that one difference between a fully testable implementation and one that is not, is that the non-fully-testable one would (or could) have larger blocks of code, where logically relevant portions are physically together, whereas, the fully-testable one would have to break up these larger chunks into smaller methods such that each piece can be individually tested, so in the event of refactoring, your tests can tell you not only that there is a problem, but precisely where that problem is.
Can someone comment on whether this is true or not?
And if this is true, would there not be at least some costs (support & "readability", at least) associated with that?