The Unity Assertion Library
Unity 5.1 shipped with a brand new Assertion Library. In this post, we will explain what an assertion is and how you can use it to improve runtime error diagnostics in your games.
What is an assertion and why should I care?
An assertion is a method that checks for a condition. If the condition is true, the method returns and the execution continues. If something unexpected happens and the assumption in the condition is not met, a message is printed that shows the callstack and optionally a user specified message. Let’s look at an example:
//Make sure the player GameObject is active
Assert.IsTrue(playerGameObject.isActive, “Player GameObject is not active”);
If the referenced GameObject was not active, an error log message would be printed showing the callstack and specified message “Player GameObject is not active”.
Many developers know asserts from unit tests. In a unit tests written using the Arrange-Act-Assert pattern, it’s the final part of the test method, where you compare expected and actual results. Assertions are not just for tests, though. You can use them in production code as well to get warned, at runtime, when invariants are violated. However, not all asserts should be used in runtime code.
What about the assertion libraries from unit tests frameworks?
It is very likely that you have first encountered assertions in a unit tests framework. As an example, let’s take NUnit. NUnit has a rich and battle-tested library for asserting tests you write with it. A natural thing to ask is why wouldn’t you simply want to use this library to test your production code? There are few reasons for that and one simple answer: it’s not meant for that purpose.
NUnit assertions allow you to test many things. From simple equality comparisons through more complex operations on collections to testing throwing exceptions. That is all fine but it all makes it too slow for using it in runtime. Low level assertions need to be as lean as possible and not give any unnecessary overhead in execution. The assertion library was written to run with no extra memory allocation and unnecessary operations.
An important thing for an assertion library is the possibility to strip the method calls out from the release build. The assertions can be very useful for developers during the production, but will be meaningless for the end-users if they fail. When building your final build you would want to get rid of all the calls to assertions. You could potentially comment all of the code out, but that wouldn’t be too smart. Luckily, .NET has a conditional compilation mechanism for such situations. The assertions library is implemented with Conditional attribute that will only include the assertion call in the developer’s build of your players. It is, however, still possible to include the assertions by forcing it via a compilation option.
Last but not least, it’s common for unit test assertion libraries to be based on exceptions. An exception is thrown on a failure and the execution flow is broken. This, obviously, is not desired in runtime code. The assertion library has been integrated with the Unity logging system and in case of a failure, a message will be logged. It makes the library versatile for all the platforms Unity supports. It also means the assertions work on AOT platforms that do not support exceptions.
So, what is in the library?
The library offers a several type-specific comparison methods and a generic equality comparer. Some of the assertion methods:
- AreEqual – generic comparer used for basic equality comparison. Uses default equality comparer.
- AreApproximatelyEqual – approximate comparer that tolerates comparison error. Can be used to compare floating point numbers.
- IsTrue – for quick and easy boolean variables checks.
All the methods can be found in the Assert documentation.
A cool thing about this library is it’s out-of-the-box compatibility with Unity Test Tools. Without any extra effort, the assertion will fail any integration tests calling the code guarded by them.
Extending the library
When you want to get the most out of a feature, it’s natural to want to extend it. The library’s AreEqual methods allow you to pass your own implementation of a comparer for a specific type. The comparer has to implement the IEqualityComparer interface.
The library comes with FloatComparer used for comparing floats. It also allows you to do comparison with a relative error check. This comparer is used by AreApproximatellyEqual method.
Using assertion library to protect your code from bugs and undesired state is an easy and little-impact mechanism you can start using right away. The library will be improved with time and, as usual, your comments and suggestions are more than welcome!
7 ComentáriosInscrever-se nos comentários