Hacker News new | ask | show | jobs
by TheNewAndy 525 days ago
You will be pleased to know that you are not the only one who does this.

I previously went down the rabbit hole of fancy unit test frameworks, and after a while I realised that they didn't really win much and settled on something almost identical to what you have (my PRINT_RUN macro has a different name, and requires the () to be passed in - and I only ever write it if the time to run all the tests is more than a second or so, just to make it really convenient to point the finger of blame).

The thing that I do which are potentially looked upon poorly by other people are:

1) I will happily #include a .c file that is being unit tested so I can call static functions in it (I will only #include a single .c file)

2) I do a tiny preprocessor dance before I #include <assert.h> to make sure NDEBUG is not defined (in case someone builds in a "release mode" which disables asserts)

2 comments

This test/src separation always felt like html/css to me. When still using C, I wrote tests right after a function as a static function with “test_” in the name. And one big run-all-tests function at the end. All you have to do then is to include a c file and call this function. Why would I ever want to separate a test from its subject is a puzzling thought. Would be nice to have “testing {}” sections in other languages too, but in C you can get away with DCE, worst case #ifdef TESTING.
Because tests also serve as api validations. If you can't write a test for functionality without fiddling with internal details the api is probably flawed. Separation forces access via the api.
I don’t need anything to be “forced” on me, especially when this forcing is nominal and I can #include implementation details. You may need that in teams with absurdly inattentive or stubborn members, but for you-personally it’s enough to get the principle and decide when to follow it. The idea is to simply keep tests close to the definitions because that’s where the breaking changes happen.

If you can't write a test for functionality without fiddling with internal details the api is probably flawed

This logic is flawed. If you have an isolated implementation for some procedure that your api invokes in multiple places (or simply abstracted it out for clarity and SoC), it’s perfectly reasonable to test it separately even if it isn’t officially public.

I agree with all of the above. The only fancy thing which I added is a work queue with multiple threads. There really isn't any pressing need for it since natively compiled tests are very fast anyway, but I'm addicted to optimizing build times.