I'm sorry, no good title.
I'm working on a C project right now and am writing tests. I usually do a 'struct method' style of programming. So I have opaque structs (no implementation revealed outside of the .c
file) and methods that act on pointers to them. But this applies to OOP as well.
Typically, when I am unit testing I want tests to be short and self-contained. I don't strictly adhere to the one assert per test, but I try to keep them small. Usually I more strictly follow one test per method.
However, I'm running into an issue that has come up before. So, for instance, I have a stack with (struct_handle
being my opaque pointer):
int size(struct_handle);
int push(struct_handle);
int pop(struct_handle);
int peek(struct_handle);
So, I'd like to have (at least) a test for each of these 4 methods, and more over have only one assert in each of these tests. But, since my handle is opaque, to set up something like "did it pop what I pushed?" I need to rely on the push function working correctly. This is my problem, since I can't (and don't want to) access the implementation details, my tests must assume that some of my methods work when testing others.
Here are the ideas I've come up with:
- Ensure a testing order on these methods. That is, ensure that
push
works before testingpop
since we need to push before we pop.- Issues: There might not always be a good / clear ordering of the methods.
- Sometimes the methods are interdependent. How can I know push worked if I can't pop?
- On that, even if there is a bit of an intuitive ordering (I need to push and pop before I can check the size) it might not be so in the details. That is, in the implementation, push and pop both rely on size to check for errors! So testing it that way doesn't actually ensure that push and pop work well before using size.
- So, if we can't test each method individually, I can instead test overall behavior.
- I have one big test method for 'the stack functions'. Maybe it goes like 'check size is 0, try to pop empty, push to stack, check size is 1, pop that from stack, check correct value returned...'
- While this seems well and nice (and I believe it is), lacks the benefit you get from one assert (or as few as possible) per test. You might fix one thing but then there are more issues behind it that just didn't get evaluated.
Anyone had experience with an issue like this? I'm curious as to everyone's opinions. Happy to share more details / stronger examples if asked.