Unit tests are insurance for later refactoring and library upgrades. This let's you avoid premature abstractions as you can easily swap out lines of code and verify you didn't break the app. This is especially important when you aren't the person doing the future refactoring.
Tests are insurance for refactoring which doesn't change the interface that is being tested.
Refactoring usually changes interfaces. Things are factored differently. The clue is in the name.
The higher up the stack your test is, the more insurance it gives you for refactoring. The lower downs the stack it is, the more likely it is to be thrown away or heavily rewritten after refactoring.
No, refactoring shouldn't change public interfaces. The very definition of refactoring is rewriting code without changing interfaces.
> Things are factored differently.
internally
> In computer programming and software design, code refactoring is the process of restructuring existing computer code—changing the factoring—without changing its external behavior.
If you're developing a library, then refactoring shouldn't change public interfaces. If you're developing an application and you own all the code paths to the code, then refactoring could change public interfaces, as the external behavior here would be the UI.
If you literally agree with the "refactoring shouldn't change public interfaces" then we need a new word for "code improvement which doesn't change external behavior, which can mean UI", which is the more commonly needed term.
And then perhaps we could agree that "code improvement often changes public interfaces" and how this relates to unit tests.
Exactly this. It's mostly lost on engineers that unit tests are usually testing at the layer that changes the most anyway - though the pain is felt once any real refactoring effort begins.