Hacker News new | ask | show | jobs
by ric2b 846 days ago
If by "smallest pieces of the system" you mean something like individual classes then you are definitely testing implementation details.

Whenever you change a method's parameters in one of those internal classes you'll have unit tests breaking, even though you're just refactoring code.

Unit testing at the smallest piece level calcifies the codebase by making refactors much more costly.

3 comments

> If by "smallest pieces of the system" you mean something like individual classes then you are definitely testing implementation details.

No, there's nothing definite about that.

The "unit" itself is a matter of perspective. Tests should be written from the perspective of the API user in case of the smallest units like classes and some integration tests, and from the perspective of the end user in case of E2E tests. "Implementation details" refers to any functionality that's not visible to the user, which exists at all levels of testing. Not writing tests that rely on those details means that the test is less brittle, since all it cares about is the external interface. _This_ gives you the freedom to refactor how the unit itself works however you want.

But, if you change the _external_ interface, then, yes, you will have to update your tests. If that involves a method signature change, then hopefully you have IDE tools to help you update all calling sites, which includes application code as well. Nowadays with AI assistants, this type of mechanical change is easy to automate.

If you avoid testing classes, that means that you're choosing to ignore your API users, which very likely is yourself. That seems like a poor decision to make.

Congrats, you understand what "unit test" was originally supposed to refer to. This is not what it's commonly meant to most people for years. The common meaning is "test every individual function in isolation".

I think this came about because of people copying the surface appearance of examples (syntactic units, functions) and not understanding what the example was trying to show (semantic units), then this simplification got repeated over and over until the original meaning was lost.

> If by "smallest pieces of the system" you mean something like individual classes then you are definitely testing implementation details.

If your classes properly specify access modifiers, then no, you're not testing implementation details. You're testing the public interface. If you think you're testing implementation details, you probably have your access modifiers wrong in the class.

If I change something at the lowest level in my well abstracted system, only the unit tests for that component will fail, as the tests that ‘use’ that component mock the dependency. As long as the interface between components doesn’t change, you can refactor as much as you want.
I prefer having the freedom to change the interface between my components without then having to update large numbers of mocked tests.
Sure, that's a tradeoff that you make. Personally I update my implementations more often than I update the interfaces, so I'm happy to take that hit when modifying the interface in trade for knowing exactly where my implementations break.