Chamois - Fluent Assertion Syntax for C++

Published September 13, 2014
Advertisement
One library that I love in .NET is Fluent Assertions. It takes assertion syntax in Unit Tests and wraps it up in a natural language syntax. Doing so, we get a nice looking structure for our test that reads like a requirement, rather than a bunch of code.

For example:[quote]Quote
[font='courier new']assert(my_variable == true);[/font][/quote]

Sure, it's nice and tearse for a programmer, but what if it were more fluent?[quote]Quote
[font='courier new']Assert::That(my_variable).Should().BeTrue();[/font][/quote]



Or a scenario where we want to check a range:[quote]Quote
[font='courier new']assert(!(my_variable >= min_value && my_variable <= max_value);[/font][/quote]



Oh crap, now we're getting more complex! But with a fluent syntax, it makes it more readable.[quote]Quote
[font='courier new']Assert::That(my_variable).Should().BeInRange(min_value, max_value);[/font][/quote]


Inspired by the brilliant .NET Fluent Assertions, I created Chamois, a header-only Fluent Assertion library for C++ Unit Testing.

The primary ways of expressing a test is as follows:[quote]Quote
[font='courier new']Chamois::Assert::That().Should().Be();
Chamois::Assert::That().Should().NotBe();[/font][/quote]


I currently support the following types:

  • Integral numerics (short, int, long, float, double)
  • String (via std::string/std::wstring, including const char* / const wchar_t*)
  • Arrays (simple arrays)
  • Pointers (naked pointers only)
  • Any object by reference that supports the equality operator

Support for more standard library containers, smart pointers, etc is planned.



Currently, I only support the Microsoft's test framework assertions but I'll be adding more soon - including c-style assert for simple tests.
4 likes 6 comments

Comments

Migi0027

This is great

September 13, 2014 09:53 PM
ongamex92

why not just implement bool inRange(T,T,T) and then assert(inRange(x, min, max)); it is more than obvious that
Chamois::Assert::That(<actual_value>).Should().NotBe(<expected_value>); is bad because it introduces new complexity and imho it isn't more readable than assert(>= <)

September 14, 2014 07:47 AM
Geometrian

I don't mean to sound insulting, but that looks a lot less readable to me. I don't know if it's just me.

Maybe you could get used to it, but I don't like chained methods. A simple "<" is much more clear to me than "LessThan". It's less for me to parse, and I think in symbols instead of English when I'm doing anything vaguely mathematical.

September 16, 2014 05:30 PM
colossal

I don't mean to sound insulting, but that looks a lot less readable to me. I don't know if it's just me.

Maybe you could get used to it, but I don't like chained methods. A simple "<" is much more clear to me than "LessThan". It's less for me to parse, and I think in symbols instead of English when I'm doing anything vaguely mathematical.

Completely agree with you. The proposed syntax in this article is FAR too verbose. If an individual really has problem reading just simple assertions, then they need more experience in the language. If the assertions are too complex to be readable, then the assertions need to be broken up into simpler statements that are asserted individually.

Code readability comes from isolating statements of computation and keeping them simple. That might be more lines of code, but it is far easier to read than just appending more and more function calls to make the code look like a sentence

September 16, 2014 11:48 PM
Althar

I can understand the advantages of having a more verbose version if it is mainly for use with Unit testing. On the other hand, I will agree to agree with the others in that I find reading operators and binary expression easier than the more verbose approach.

Another aspect which I am not entirely convinced about either is the fact that the asserts are built from several function calls. I tend to prefer inline implementation which when hitting an assert will break into the calling code, rather than a few scopes down.

I wouldn't mind seeing it used in a concrete Unit Test sample to have a feel for it though.

Keep it coming!

September 18, 2014 05:34 PM
ptroen

I tend to use try catch throw instead of assertions in my unit tests since sometimes those tests will show in working code?

So take the above example:

assert(my_variable == true);

<=>

if(my_variable!=true) throw MyVariableIsNotTrueException();

and catch it some where possibly?

But all approaches raise the question what you trying to do in the unit test. For the author here it seems it has to do with READIBILTY.

I tend to agree it's a bit less readable cause of the namespace in front(but that could be removed with a using) and Should() tends to be vague but makes sense from a literal word. Wolud be nice tho if you could use the cast operator and then you could make should behave like a C# property in C++ :)

Digging a little deeper you could also make it more readable by aligning with a mock in a vector input output model for your unit test. Much easier to administrate imho. IE

Mock looks like this

| Input1 Input2 ...| | Input1 Input2

| .... |

| Output1 ...Output2 | <==>| foo(Input1) foo(Input2)

LHS RHS

if LHS and RHS equal test passes

Then you could use remaining unit tests to prove the rest

Once you get your heard around vectors imho it's MORe concise. The problem with english rules is it's great for short set of rules. When it spans many pages it can just take up alot of time and potentially more difficult to debug

Cheers,

Patrick :)

September 19, 2014 08:45 AM
You must log in to join the conversation.
Don't have a GameDev.net account? Sign up!
Advertisement