Poorly written tests make refactoring nigh impossible, and usually don't contribute to anything other than code coverage metrics.
Focus on quality, not quantity.
Poorly written tests make refactoring nigh impossible, and usually don't contribute to anything other than code coverage metrics.
Focus on quality, not quantity.
But type systems do not help you with things like "do we gracefully fail when we got this error path?" or "do we actually drain the queue in all cases?".
Few things but contrived tests do, really.
And your second example is a very usual thing to do with them.
(The first isn't common, but is doable, it's common to use types to enforce that failure is handled, not that it fits some extra requisites.)
High level refactoring means writing new tests. Which often kills the effort before you begin.
It's a widespread problem that people can end up talking past each other, since they make assumptions about the definitions of terminology that other people are using.
I've written about this e.g. http://chriswarbo.net/blog/2017-11-10-unit_testing_terminolo... and http://chriswarbo.net/blog/2020-07-07-more_testing_terminolo...
My own use of the equivocal language "I think" didn't help here. That was a bit of classic British understatement. But really, the two comments we're talking about are unambiguous.
invalidOrTaken's claim that refactoring can affect what is internal versus external, or that it can be context-dependent, was surprising to me. I would consider changes to what's internal versus external as breaking changes; large changes could plausibly be called redesigns. Certainly not refactorings.
The context-dependence of internal/external makes sense, but that makes me think in terms of e.g. "MySQL is external to the application" versus "MySQL is inside the application's container", or even "MySQL is interal to the subnet where the application runs". Architecturally that makes sense, but I don't think it would affect the way I test things, or classify those tests.
On the other hand, invalidOrTaken might be using "external" to mean "other classes", in which case it's easy to imagine a refactoring changing all sorts of (class) boundaries. Likewise, the phrase "external behaviour" could simply mean "the public methods of a class".
I've certainly worked somewhere that claimed to follow "Behaviour Driven Development", where each "behaviour" was a micro-managed implementation detail of a particular method of a class, with a huge pile of mocks to simulate the behaviour of everything else.
The "external" interface, as in, the API presented by the library, mostly did not change. But internally blocks were broken apart, new ones formed, and logic ripped from one function and placed in another.
To someone seeing the whole, or "the library," changes were 99% internal (some changes in how options were interpreted).
But from the perspective of any one function, boundaries were crossed quite promiscuously, and if we'd had unit tests for them, we'd have needed to (re-)write some.
It's my experience that we are not very good at saying, "THESE are the chunks into which the program should be divided and thought of," and then never altering from that. There's always some cross-cutting concern that comes up. For this reason, I am suspicious of unit-testing-by-default, as "what is a unit" is often in flux.
To verify this invariance, you have to test it. Specifically, and that means new tests.
That raises the question how valuable the skill of writing-good-tests is. For quality software or is. For a career unfortunately not in many companies.