I also like the fact that you can put unit tests for helper functions that are inside of other functions. This means you can use the inputs to your outer function as part of the tests for an inner function, which has been hard to do in the past.
Because this leads the way to being able to verify that your functions will act as expected in all cases, rather than just for the ones that you thought about when you were writing unit tests.
A classic approach is that if you have to make some complicated API call with a bunch of arguments, you can put all the logic wrangling the arguments into a pure helper function and unit test the helper.
I like the idea of attaching tests to the function itself - oftentimes I'm finding myself combing through the unit tests for various components to understand the expectations around how they are meant to be used (especially when they are not documented well enough), I feel this approach could help in this aspect (and also with adding new test cases that could have been missed).
Yeah, that's fair. The benefits of unit tests for me were always that they forced me to decompose the problem into testable/side-effect-free functions. But this thread is about questioning the value of that in the first place.
Just so long as the outer function is testable and side-effect-free.
C++ gives you enough access control so you can expose things just for testing if you want (make the test a friend, encapsulate the functions into another class). You can do this without breaking encapsulation.
If the functions are capturing a lot of variables, then I would try to reconsider the design. Usually things aren't irreducibly complex.
I don't exactly follow your last paragraph, but tests aren't just something you throw away when they pass. So if I were to write tests for the helper functions, I wouldn't delete those tests on a refactoring pass in order to use nested functions.
Why would you need to do this for a unit test? Can't you just test the properties of the return value of the outer function like you would for any other value? If the function returned an object, how would that be different?
You write unit tests for units of code. A function with nested functions inside of it is a single unit of code; that's essentially what those functions being nested, and hence not directly invokable from the outside, indicates.
Having unit testing built-in to the programming language and tooling is a huge plus, absolutely. I don't know who originally came up with this, but I swear, it would be worth some recognition :) (And thankfully, whoever did originally come up with this idea, it has been copied a ton by the recent crop of programming language designs.)
Beyond unit tests, this seems like a great opportunity to leverage property-based testing, at least for pure functions; checking that both versions return the same results is an easy property to think of.
A simple example might be a function that makes an HTTP request to a server. You could separate out a function that builds the request from a function that sends the request to the server. Then it's easy to unit test that the request is what you expect, without coding up a realistic fake for the server.
reply