4 ms·
> It's obvious if you change a "unit" of code, its tests are going to fail. No it's not. Not at all. The whole point is you can change the guts of a unit arou
by njharman 11y ago
> It's obvious if you change a "unit" of code, its tests are going to fail.
No it's not. Not at all. The whole point is you can change the guts of a unit around and know you haven't broken things cause the unit tests still pass. Because the unit test is testing the "contract" (explicit or implied) the unit has made with other units about it's inputs and outputs.
Unit test should fail (and require updating) only if the unit's INTERFACE changes.
But, if your unit tests are failing everytime you touch your code then 1) your code is not cleanly isolated and independent and/or 2) you have poor unittests.
- kazinator 11y agoIf nothing in an application depends on some aspects of the behavior of a unit interface, what is the point in testing it? You only need that sort of test in a programming language or public library, because you're publishing the behavior to unknown numbers of users, and it has to work, as documented. If they find too many things that don't work according to the documentation, they will correctly suspect that you aren't testing, and lose confidence. But if some API is internal to an application, and no code depends on some aspect of its interface contract, then that aspect effectively doesn't exist. It may happen that someone discovers this aspect in the documentation and tries using it. At that time it is either found broken, or found working. If it is found broken, it can be fixed. Or else it can be striken from the documentation (and another way can be found in the application code to meet its requirements). If the aspect is found correct, or fixed to reflect the documentation, and is then used in the application, then that use constitutes a test. The feature is tested indirectly, through some regression test case which targets something in the application, which depends on that aspect of the API contract lower down. If you design units with all kinds of detailed aspects in their interface contracts which end up not being used at all, and test all of them, it can be argued that you're wasting time: you're basically working on your library design hobby, at the expense of the project, which just serves as a vehicle for it.
- prodigal_erik 11y agoUnit tests can verify assumptions that the implementation is internally relying on. E.g., say a greedy algorithm relies on a collection being sorted, even though the public interface does not return results in any particular order. If I make a mistake such that an edge case leaves the collection not sorted correctly, a test of the public API can't tell unless it happens to trigger the edge case whose importance might not be obvious.
- kazinator 11y ago> a test of the public API can't tell unless ... "Can't tell unless" means exactly the same thing as "can tell". You have a way to get to that corner case through the public functionality. If there really is no way to tell through the current public API, there the bug doesn't exist.
- prodigal_erik 11y agoI think I'm arguing for letting white-box unit tests make assertions about implementation details in a simple and clear way, rather than having to somehow devise a test using only the black-box API that happens to fail if the assertion doesn't hold. In other words, you can only guarantee parts of the internal state are valid if you know how to infer them from outside. Are you arguing that all unit tests should be black-box?
- badrij 11y agoThis reflects my experience too. Refactoring is defined as the process by which you restructure code without changing its external behaviour. So in other words, refactoring should never break tests because the external features of the code do not change. Now - redesign or rewriting code is a very different thing. Refactoring can lay the groundwork for redesign or component level rewrites. But the process of redesign and rewrites could result in breakages unless the right level of isolating layers are put in place. This usually involves lots of work to keep tests working. Personally I have found that unit tests don't result in less work. They are a LOT of work and will continue to be a lot of work if they are to generate value. What they offer though is the ability to know when things have gone wrong and the confidence to release and deploy. I realize that you don't get increased confidence in your release process by doing less work. Software it appears, like almost everything else, obeys the basic laws of thermodynamics. :)
- jameslk 11y agoI think the problem here is that I didn't specify exactly what I meant by "refactoring", "unit" and what types of changes I would be making. Often times I find refactoring necessary because a significant piece of the system was either under or over engineered and it becomes necessary to update that code without changing the functioning of the system. So by refactoring, I mean refactoring at a level the encompasses multiple units of code, while maintaining the same functioning of the system. That means the interfaces may change for the individual units, which would obviously break the unit tests.
- kazinator 11y ago> you haven't broken things cause the unit tests still pass And what are those "things" that haven't broken? Why, unit tests.