As a fan of regular types and value semantics, I'm keen on classes becoming more regular and being non-polymorphic. As a fan of non-throwing operations, I'm keen on operations being noexcept. I also appreciate confirmation of what special member functions are actually being generated by the compiler. And I'd like to track these things along with code these are associated with.

C++ offers the <type_traits> header file which offers classes for checking qualities like these and I've found myself enjoying making use of them in unit test code like the following:

TEST(MyClass, Traits)
    EXPECT_TRUE(std::is_constructible< MyClass >::value);
    EXPECT_TRUE(std::is_nothrow_constructible< MyClass >::value);
    EXPECT_FALSE(std::is_trivially_constructible< MyClass >::value);

    EXPECT_TRUE(std::is_copy_constructible< MyClass >::value);
    EXPECT_TRUE(std::is_nothrow_copy_constructible< MyClass >::value);
    EXPECT_FALSE(std::is_trivially_copy_constructible< MyClass >::value);

    EXPECT_TRUE(std::is_move_constructible< MyClass >::value);
    EXPECT_TRUE(std::is_nothrow_move_constructible< MyClass >::value);
    EXPECT_FALSE(std::is_trivially_move_constructible< MyClass >::value);

    EXPECT_TRUE(std::is_copy_assignable< MyClass >::value);
    EXPECT_TRUE(std::is_nothrow_copy_assignable< MyClass >::value);
    EXPECT_FALSE(std::is_trivially_copy_assignable< MyClass >::value);

    EXPECT_TRUE(std::is_move_assignable< MyClass >::value);
    EXPECT_TRUE(std::is_nothrow_move_assignable< MyClass >::value);
    EXPECT_FALSE(std::is_trivially_move_assignable< MyClass >::value);

    EXPECT_TRUE(std::is_destructible< MyClass >::value);
    EXPECT_TRUE(std::is_nothrow_destructible< MyClass >::value);
    EXPECT_FALSE(std::is_trivially_destructible< MyClass >::value);

    EXPECT_TRUE(!std::is_polymorphic< MyClass >::value);

As unit test code that's also going into my source code revision system, this has the advantage of tracking these qualities along with the code being committed for MyClass. I also like getting a gamification kick of out seeing classes take on more of these qualities - which I do using code like this.

I wonder however: are there other ways to achieve this that perhaps have more benefits without as many pitfalls?

Here's some concerns that I have about this technique:

  1. Are these acceptable as unit tests? They are to me but are they to others? While the definition of unit testing which Wikipedia provides seems subjective enough for this to qualify, I'm concerned here how widely others would agree.
  2. Would it be better to track these qualities elsewhere like in the class's code itself by using static_assert for example? This is different from the last concern in now focusing on whether their's a better place (not whether other software developers would accept this as unit testing). Tracking these qualities in the class's code via static_assert instead of in unit test code like shown, seems like an elevation of these qualities importance. For more performance critical classes that direction makes some sense. I also recognize a perspective that these should instead be lowered in importance to perhaps just being warnings or messages (instead of test failures or build failures).
  3. Lack of scalability. Is it more boilerplate code than it needs to be? It's an easy copy and paste operation to create tests like this but it doesn't lend itself to global updates. I'd prefer to abstract this more if possible so there was a single place it could be updated from. I've considered converting this into a template function that combines these checks and just gets the type as its template parameter. How would that track the true and false values however? It could generate an output report but that seems cumbersome to parse back into EXPECT_* contexts with local line numbers. A macro function meanwhile would be evaluated in the unit test's context but a multi-statement macro function still shows up as all on one source code line: the line where the macro is called from. I've also considered combining the normal, nothrow, and trivially forms of these checks, into single line checks taking a parameter to indicate which of these should apply in the positive. I haven't seen anything more satisfying yet than the shown pattern however.
  • 2
    Would you consider it an error if one of these tests fails? It's one thing to do a check to ensure that there likely won't be problems, but I don't know if unit testing is the place for this.
    – Neil
    Dec 24, 2018 at 7:18
  • 1
    Is it really a requirement that your class is NOT trivially constructible?
    – D Drmmr
    Dec 30, 2018 at 16:36
  • @DDrmmr It's not a requirement, no. And as perhaps you're suggesting, it wouldn't make as much sense to me as a requirement as the reverse. It does however make the fact that a class is not trivially constructible trackable. The question being how else might trait values be tracked especially towards motivating things like more-triviality. Jan 4, 2019 at 14:25
  • @DDrmmr by the way, I do like your question and have upvoted it since I do see it as a question useful to think about in the context of my post. Jan 4, 2019 at 14:26
  • @Neil Similar to my response to D Drmmr's comment, I do consider there being a degree of error worthiness to these failing depending on what exactly particular check was testing. I.e. a class failing to be non-trivially constructible being more a good thing IMO and in this context less an error. A class whose doxygen "contract" said it had standard layout or was supposed to be default constructible being examples where failing seem more error worthy. Using unit testing for tracking traits is agreeably not entirely to my liking though. But neither is using static_assert. Jan 4, 2019 at 14:43

3 Answers 3


If these traits are part of the type's interface, they should ideally be asserted close to the declaration of that type. A static_assert is the ideal way to do that, since compilation will fail (rather than just your tests).

In general, tests are useful for checking certain properties of your program by example. They cannot typically show that a program is bug-free, but may be useful to find bugs if any are present. In contrast, type systems provide an automated proof of correctness properties. Because the type system is a proof (rather than just an example scenario), it is usually vastly preferable to use type-system level checks where possible. Here the type traits are type-system level properties, not runtime properties. Checking them as part of a unit test suite is not wrong, but I find it confusing.

  • +1 for answer. Agreed for when these traits are part of the type's design. Reminds me of motto: save run time checks for what can't be done at compile time. Doesn't seem as appropriate from perspective of motivating regularity over libraries of types or confirming what compiler's indeed auto-generating however. Here operations not being noexcept for example isn't deal breaker; just less desirable perhaps. Ideas for that? How about a doxygen comment generator program that checked types & generated documentation re. current traits? Dec 24, 2018 at 19:01
  1. Are these acceptable as unit tests?

No. These are not acceptable unit tests. Unit tests should check behaviour rather than implementation. The unit test you have is not checking any behaviour of MyClass.

Suppose I am another developer with doesn't really care about your regular types in your software suite, and I for some reason want to remove the copy constructor. My code compiles but all of a sudden this unit test fails. What do I do now? Probably remove the unit test and go on. And if I write a new class I wouldn't even consider for a second to add these tests.

  1. Would it be better to track these qualities elsewhere like in the class's code itself by using static_assert for example?

For sure, the static_assert is a better solution than a unit test (if that's even possible to implement). But I still think it is useless. Partially for the same reason as the unit test. Would another developer in your team add them? You'll probably end up copying all your asserts every time, or creating an ugly macro generating them.

  1. Lack of scalability. Is it more boilerplate code than it needs to be?

You have identified the most serious problem. And suppose you want to change anything in your code standards, then you need to update not only all your classes, but also all tests or assert that you copied. Wait, did I mention code standards? Yes, I think this should be part of your code standards. A team typically defines code standards on how to code. This is not only code style (which you obviously need to agree about), but also things like obeying the rule of zero, or not using protected member variables, or have your classes behave as regular types. Next, you have a review system where other developers check the compliance with these code standards. Yes, one may slip through, but with the testing and asserts without review you don't have any guarantee either.

  • 1
    Agreed lack of scalability is most serious problem. Also agreed unit testing is more useful when used to test noticeable behavior. While I recognize a perspective that these aren't unit test worthy, I'll disagree with a black & white position on this. Whether class is default constructible or copy assignment is noexcept are indeed noticeable behaviors. I don't want to split hairs though over what unit tests should test as much as get ideas for better solution. I'm leaning towards a static code analysis tool that generates reports & tracks changes. Opinions/recommendations on that? Jan 4, 2019 at 15:08
  • A static analysis tool is something that can assist you in a code review. I've used it in teams to check on code style (more for the developer before offering it for review than for the reviewer). This seems a good solution to remain consistent.
    – Bernhard
    Jan 5, 2019 at 0:58

I, too, have a preference for regular types and value semantics. But I don't encode preferences into unit tests. Unit tests exist to enforce the requirements. Very occasionally, the best way to do something could be precluded by one of these preferences, so it's important that unit tests don't appear to create unnecessary implementation constraints. Another developer on your project might see your constraint in a unit test, believe it to be a requirement, and therefore rule out the best solution.

If the result of a traits query is part of the contract of your object (e.g., that the object is nothrow move constructible), then it's reasonable to check that in your unit tests, since unit tests document and test all of the other contractual promises. (In fact, if you use test-driven development, then a unit test is absolutely the right place, because you first encode a requirement as a test, then ensure that it fails, and finally write/modify the implementation to make it pass.)

It's also better to fail at compile time than at test time or run time, so by all means use a static_assert when you can.

These two positions are not mutually exclusive: When the requirement can be tested at compile time, I'll often write a unit test in terms of static_assert.

TEST(MyClass, MustBeNoThrowConstructible) {
    // To meet complexity and thread safety requirements, MyClass must be
    // nothrow move constructible.
    static_assert(std::is_nothrow_move_constructible_v< MyClass >);

That gives both the benefit of testing all of the requirements in the unit tests and the benefit of early compile-time detection. (The unit test framework doesn't care that you didn't use an ASSERT nor an EXPECT, and will simply show that this test passed just like the others.)

The caveat here is that I have my environment set up to always build and run any test suites that depend on code that has changed. If building and running unit tests in your development environment is uncommon, and you mostly rely on your continuous integration system, then this won't work very well.

There's nothing wrong with placing a static_assert in your implementation, but sometimes there isn't an obvious place to do so. The code to achieve something like std::is_trivially_copy_constructible might be scattered in a couple different parts of your class definition. The unit test is often the best place to indicate that it's a contractual requirement.

  • I haven't tried it but can't you place the static assert(s) in a template class (that only has them) that gets to the correct type to check via CRTP and that your target class inherits from? (In fact, maybe you could just wait until C++20 and use concepts? Though I don't know much about concepts as they finally ended up in C++20 ...)
    – davidbak
    Jun 28, 2020 at 18:43

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.