Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Detecting c++ structure is updated from unit test

I have a family of data structures, that should be passed from one layer to over using boost::serialization. For example

struct DataType1
{
    std::string field1;
    std::string field2;

    template<class Archive>
    void serialize(Archive & ar, const unsigned int version)
    {
        ar & field1;
        ar & field2;
    }
};

I want to write unit test's on this, just to be sure that i did no miss some fields (there are a lot of structures and fields).

The problem is, if I add new field in structure (i will definitely do) and forget to update unit test, this field will not covered by unit test.

My question is: how to detect that structure (or class) is changed. My idea was to use static_assert(sizeof(DataType1) == HARD_CODED_VALUE) but it suffers from difference in structure size in different compilers, platforms (x64, x86) and configurations (release, debug).

Any good idea how to handle this?

like image 902
capone Avatar asked May 29 '13 10:05

capone


People also ask

Does unit test case will detect all errors in system?

Tests will not uncover every bug. Unit tests only test sets of data and its functionality—it will not catch errors in integration.

What is the recommended way to separate the code that you are testing from its related dependencies?

Mocking is a process used in unit testing when the unit being tested has external dependencies. The purpose of mocking is to isolate and focus on the code being tested and not on the behavior or state of external dependencies.

Can you unit test C?

The most scalable way to write unit tests in C is using a unit testing framework, such as: CppUTest. Unity. Google Test.

Does TestInitialize run for each test?

The method decorated by [TestInitialize] is called before running each test of the class. The method decorated by [TestCleanup] is called after running each test of the class.


2 Answers

The problem is, if I add new field in structure (i will definitely do) and forget to update unit test, this field will not covered by unit test.

My question is: how to detect that structure (or class) is changed.

My idea was to use static_assert(sizeof(DataType1) == HARD_CODED_VALUE) [...]

That is not a portable solution (as you yourself noted).

Any good idea how to handle this?

Yes: can you start with updating the test?

That is, do not decide what should go in the structure, then add it, then update tests (if you do not forget).

Instead, update tests to check for the new serialized data, then make sure the updated tests fail, and only then update the code so the tests pass.

This approach (write/update unit tests first) has been created (partly) to tackle exactly this problem.

The test-first approach has other advantages as well:

  • it neatly avoids YAGNI

  • it minimizes premature optimization

  • it evolves naturally for tracking the feature-completeness of your application/implementation.

like image 53
utnapistim Avatar answered Oct 30 '22 11:10

utnapistim


Add a comment to the class definition to remind you that you have to tweak the serializer when adding members. There are limits on what a computer could do for you -- that's why code review is important. Let any patches be reviewed by another programmer, have a rigorous set of test cases and hope for the best.

I'm sure you could e.g. write a clang plugin which will make sure that a particular method references every member of a struct, but do you really need this and can you invest your time into that?

That said, you have bonus points for trying to offload as much work to the computer as possible. Even the static_assert trick is a good one. If you protect it with a set of #ifdefs for one particular ABI and architecture where you build often enough, it might do a great job.

like image 28
Jan Kundrát Avatar answered Oct 30 '22 10:10

Jan Kundrát