The Constraint Model is the recommended model of assertions to use in NUnit 3, and it's been a part of NUnit since version 2.4.
Unlike the Classic Model where each assertion was a different method on the
Assert class, when using the Constraint model, we'll still be using the
Assert class but all the assertions start with the
So, it reads as
Assert.That, and the first parameter is the actual value, and the next parameter is the constraint that you want to apply to that value.
For example, in our first test where we wrote 'Assert.AreEqual' and then we pass the “expected” and then “actual” values.
Using the Constraint model, this becomes
Assert.That and then we pass the “actual” value, and then for the next parameter we'll say
Is.EqualTo and then we'll pass the “expected”.
That method also has the same optional parameters for including a description.
The concept of constraints in NUnit was modeled after a concept from jMock and NMock.
And I really like the way NMock describes constraints as 'mini rules'.
It frames things nicely, because the Constraint model in NUnit is more than just a syntax change. It lets you compose a series of these mini rules, and then apply them to your actual value.
As we started using the Constraint model, I wanted to draw your attention to the order of 'expected' and 'actual' values.
The Constraint model flips the order so that the 'actual' value is the first parameter, instead of the 'expected' value.
Personally, I find this more intuitive and readable, but it can be something to keep in mind if you find yourself upending existing assertions to use the Constraint model.
Now that the Assertion class is not our starting place for discovering the different types of assertions, NUnit helps you by grouping the constraints into helper classes.
Your constraint expressions will start with
For your reference, I've listed here, the methods available on all of these helper classes.
And you'll notice
Is contains the bulk of the constraints.
Is is a keyword in VB.NET, and to get around this NUnit provides the
IZ version of that class to avoid the conflict.
As you look at these helper classes, you can see that the grouping isn't really based on a particular type of assertion.
It's more aligned with how the constraint would be said verbally, as you might explain your assertion to a person.
In the Classic model, each condition you want to validate required a separate method to contain the logic for the assertion.
The Constraint model allows you to compose multiple mini rules together and use them inside a single assertion.
To do this, the constraint model provides a fluent interface that allows you to chain constraints together.
To see this will use
EqualTo as an example again.
The Classic model had two separate methods for 'AreEqual' and 'AreNotEqual'.
The Constraint model though, doesn't have a specific
NotEqual method. Instead, we use the
Not. constraint and then the
Again, I find this syntax easier to understand. You don't have to keep as much context in your head, you just read the assertion like a sentence.
There's more to it though than just readability — this flexibility allows us to create assertions that just aren't possible using the Classic model.
For example, if you want to verify an array contains just one instance of the number 3 in it, there really isn't a clean way to do this in the Classic model. You could do something like this and use the
Count method on the array, and it will pass.
But if we change the value so that the test fails, which you'll see is the failure message, just isn't very helpful.
Using the Constraint model, we can write
Assert.That and then for our constraint say
Has.Exactly 1 to 3.
And if you'd make this test fail, you can see that the failure message is much more useful.
In many cases there are different series of constraints that can accomplish the same result.
Using the same example, we can replace the
Exactly constraint with the
One constraint and have the equivalent result.
The Constraint model also provides what are called Compound Constraints.
We saw an example of this earlier when I used to
Not constraint to demonstrate
In addition to
Not, there are 2 additional compound constraints —
This allows us to write assertions with multiple conditions that will only succeed if both conditions are met.
For instance, to check if this value is more than 5 and less than 100, we can enter
Is.GreaterThan, put the value 5. And then using the compound constraint
And we can apply the
LessThan constraint with the value 100.
And if we replace
Or the test will pass, since only one of the conditions needs to be met.
This can be a useful tool, but with great power comes great responsibility.
With each compound constraint you chain together, the complexity grows, and the order of constraints can start to have an effect.
Constraints are going to be evaluated from left to right.
Also, when used in the same assertion, the
Or constraint has precedence over the
This is another case where you'll need to use your best judgment, because just because it can be written, doesn't mean you should use it.
After all, you could end up writing the equivalent of something like
Assert.That “true” is
Assert.That “true” is