4 ms·
What world do you live in where you can refactor without changing tests? I mean, it sounds like an ideal one but I’ve never lived in such a world. Tests always
by ninkendo 5y ago
What world do you live in where you can refactor without changing tests?
I mean, it sounds like an ideal one but I’ve never lived in such a world. Tests always seem to couple to the way code is currently organized, and I can barely imagine any refactoring change that wouldn’t require some changes in my tests.
- Jtsummers 5y agoIt depends on your tests. Your integration tests should never be impacted by a refactor, or it's not a refactor (using the definition that refactors don't change interfaces). The tests need to be rerun, but they shouldn't be changed. Your unit tests and sub-integration tests (integration of multiple units but not the whole) may be impacted by some refactors, though, but that's pushing the definition of a refactor. Your public interface to your lower level modules/classes are the only things you need to directly test. If that's your smallest unit for testing, then a refactor should also (again, in theory) not impact them because the refactor should not change that public interface, at most changing the internal (private) functions and structure which the existing tests can verify just as they verified the unit before. If you restructure your units (split a unit into two, for instance) then you'll have to change your unit tests and possibly some integration tests if you instantiated the previous unit directly as part of the test. But that's pushing the definition of a refactor.
- Chris_Newton 5y agoIf you use very low level tests then sure, maybe you need to adjust your tests to match the adjustments in the rest of your refactored code. But since by definition a refactoring does not change the code’s observable behaviour, no tests above that level should be affected. I find that very low level tests tend to be fragile and have limited value in most situations as a result, so I don’t personally tend to use them much, but YMMV.
- eyelidlessness 5y agoI routinely refactor without changing tests, and it’s a primary concern when I define interfaces and determine what to test. For what it’s worth: - This works best if you actually embrace BDD to test for behavior rather than results. The behavior is less likely to change, and along with points below so too are the interfaces under test. - I find the least test change in statically typed languages where defining types is the first “test”. Behavioral interfaces become much more stable as you define them if you actually know what they are upfront. - Both of the terms “integration test” and “unit test” discourage this. Validating what your program actually does usually sits somewhere in the middle, and allows you to encapsulate a lot more of what would otherwise likely change in tests. - Stricter interfaces fare better than looser. That doesn’t mean give up on the Robustness Principle, but it does mean don’t let it become infectious (I now want to blog about the “color” of functions which accept “options” or other miscellany). The sooner you parse/validate/have concrete and reliable types, the less your code under test and the tests themselves will change. And that, while it’s my last point, is the most important: narrow types early. Get stability inside the seams of your program.