You do not have to test with the finest possible grain.
Many current discussions of unit testing are based on a tradition (XP) in which functions are added incrementally, In other words, almost everything starts as a "simple" function, and many of these simple functions become more complex over time.
From this point of view, it makes sense to perform tests for simple functions.
But … we ideally do not test functions, but behaviors. It is not necessarily important to us how a particular behavior is achieved. If we reduce the coupling to the implementation details, these details can be changed more easily.
In other words, if we take a well-tested module and extract a simple method from it, we do not necessarily have to run and do a bunch of new tests for that module – the behavior we're interested in is already covered by this. We have tests for the code calling the new function.
In the case you describe, you actually go the other way (which is fine); After extracting simple functions everywhere, you have the code that is trivial. From a design point of view, this is great – trivial code is really easy to understand.
Hoare wrote code that is "so simple that obviously there are no shortcomings". In a tdd approach, we tend to work on designs that isolate code that is being tested (for example, I / O) in modules that fail too easily, and ensure that the complicated logic exists in easy-to-test components.
That is, choosing between two alternatives based on a Boolean condition is not really expensive to test, so the resulting design usually arrives at a point where the logic works is measured by a "unit test".
But the subject of this test would probably have a larger grain size than a single if condition.
I can only test if I test the current implementation
Let me try a slightly different way of writing: Yes, we are currently testing an implementation. Running the test will observe the behavior of the current implementation and then check if this behavior meets the documented constraint.
We measure the implementation by a restriction of the behavior.
If I run the zoo, maybe we have a test that looks something like this:
selected = isSelected(id)
The test does not care if
OpenMenu is a single monolithic method, or if it delegates the work to smaller parts. It is absolutely not a "how" as long as the required API is provided and a satisfactory result is achieved.