English 中文(简体)
Unit testing opaque structure based C API
原标题:

I have a library I wrote with API based on opaque structures. Using opaque structures has a lot of benefits and I am very happy with it.

Now that my API are stable in term of specifications, I d like to write a complete battery of unit test to ensure a solid base before releasing it.

My concern is simple, how do you unit test API based on opaque structures where the main goal is to hide the internal logic?

For example, let s take a very simple object, an array with a very simple test:

WSArray a = WSArrayCreate();
int foo = 5;
WSArrayAppendValue(a, &foo);
int *bar = WSArrayGetValueAtIndex(a, 0);

if(&foo != bar)
    printf("Eroneous value returned
");
else
    printf("Good value returned
");

WSRelease(a);

Of course, this tests some facts, like the array actually acts as wanted with 1 value, but when I write unit tests, at least in C, I usualy compare the memory footprint of my datastructures with a known state.

In my example, I don t know if some internal state of the array is broken.

How would you handle that? I d really like to avoid adding codes in the implementation files only for unit testings, I really emphasis loose coupling of modules, and injecting unit tests into the implementation would seem rather invasive to me.

My first thought was to include the implementation file into my unit test, linking my unit test statically to my library.

For example:

#include <WS/WS.h>
#include <WS/Collection/Array.c>

static void TestArray(void)
{
    WSArray a = WSArrayCreate();
    /* Structure members are available because we included Array.c */
    printf("%d
", a->count);     
}

Is that a good idea?

Of course, the unit tests won t benefit from encapsulation, but they are here to ensure it s actually working.

最佳回答

I would test only the API, and focus on testing every possible corner case.

I can see the interest in checking that the memory structures hold what you expect. If you do this you will be tightly coupling the tests to the specifics of the implementation and I think creating a lot of long-term maintenance.

My thought here is that the API is the contract and if you fulfil that then yoru code is working. If you change the implementation later then presumably one of the things you need to know is that the contract is maintained. Your unit tests will verify that.

问题回答

Your unit tests shouldn t depend on the internal details of the code that they re testing. Your initial example is actually a pretty good test. It does one thing, then verifies that the state of the object is as expected.

You d want to create tests that verify the behavior of other parts of the API as well, of course. Fir example, in the array case, you d want to have test cases that verify that the length if the array is reported correctly after adding and removing items.

Writing unit tests that depend on an exact match with a known good memory snapshot is generally a really bad idea, in that every implementation change will cause the tests to fail. If you do decide to use snapshot-based tests, make sure there s an easy to regenerate the "known good" snapshots.

I would suggest splitting the unit testing into white box and black box unit testing. The white box testing focuses on the API interface, and correctness of results, while the black box testing focuses on the internals.

To facilitate this I use a private header (e.g. example_priv.h), with a #ifdef TESTING for function prototypes that are other internal / private. Thus you can exercise internal functions for unit testing purposes, without exposing them in the general case.

The only loss with this method is losing the ability to explicitly label the internal functions as static in their source file.

I hope that is helpful.





相关问题
Fastest method for running a binary search on a file in C?

For example, let s say I want to find a particular word or number in a file. The contents are in sorted order (obviously). Since I want to run a binary search on the file, it seems like a real waste ...

Print possible strings created from a Number

Given a 10 digit Telephone Number, we have to print all possible strings created from that. The mapping of the numbers is the one as exactly on a phone s keypad. i.e. for 1,0-> No Letter for 2->...

Tips for debugging a made-for-linux application on windows?

I m trying to find the source of a bug I have found in an open-source application. I have managed to get a build up and running on my Windows machine, but I m having trouble finding the spot in the ...

Trying to split by two delimiters and it doesn t work - C

I wrote below code to readin line by line from stdin ex. city=Boston;city=New York;city=Chicago and then split each line by ; delimiter and print each record. Then in yet another loop I try to ...

Good, free, easy-to-use C graphics libraries? [closed]

I was wondering if there were any good free graphics libraries for C that are easy to use? It s for plotting 2d and 3d graphs and then saving to a file. It s on a Linux system and there s no gnuplot ...

Encoding, decoding an integer to a char array

Please note that this is not homework and i did search before starting this new thread. I got Store an int in a char array? I was looking for an answer but didn t get any satisfactory answer in the ...

热门标签