all Technical posts

How to make test-asserted operations

Operations running during the test assertion differ quite a bit from regular operations in the implementation. The goal is different. It is important to be aware of this when creating test assertions.

Begin with the operation

First step would be to identify what the test assertion needs. Is it reading a file? Compare contents? Counting items? This represents the operation itself, the core action taken. If this operation would be part of the implementation, and not the test assertion, we would maybe introduce an interface and error types as to not expose internal failures to the user. This differs a lot if the operation would run during the test assertion; as in that case, there is need for a lot of internal context – otherwise, the test assertion is not very useful.

🚩 Only if the source code is at the same authorization level as the test output, should the internal context be exposed.

Fire your life coach

One of the defensive code techniques is called ‘fire your life coach’. In short, it means that you should always prepare for a failure. In writing operations within test assertions, this is even more the case. If we take the example of reading a file contents during the test assertion, there are a lot of things that could go wrong: the file could be missing, the contents too big, the wrong extension, the wrong format, the wrong schema… Each of those verifications should be be checked, but moreover, each of those verifications should have a test assertion failure that includes enough internal context so that the failure makes sense. If the file is missing, you should include the file name and the directory where the system has searched; if the file is too big, you should show the maximum allowed contents and the actual contents length; if the file has the wrong extension, you should show the expected extension and the actual one.

It is not enough to have a yes/no test assertion verification, as you always need to know what went wrong and why it went wrong.

Expose your test-asserted operation

Once the operation is acting as an assertion, it is time to think about reusability. In almost all cases, the assertion is too big to be exposed directly to the test. Therefore, think about readable and usable ways of exposing the assertion to your test. If your system uses a test framework with a lot of Assert.XXX methods, then you could place your file assertion in an AssertFile.XXX one. Same goes if your system is using extensions on existing types for their assertions, you can create a new extension for your file assertion.

It is important that you treat your operation as an assertion all the way, because that is what it becomes: a test assertion.

Conclusion

This post talked about how functionality in implementation code differs from test code. When an operation is run as a test assertion, a lot can go wrong and all those failures need to be exposed to the tester in a humanly readable manner. Treat your operation as an assertion, because that is what it is. It even goes further. Every single line of code that gets executed after the interaction with the SUT (system-under-test) could be considered an assertion. It does not matter if it is considered ‘infrastructure code’, if it gets run in the test, it looses its roots and grows into a test assertion. And every test assertion needs good failure management and be exposed like any other assertion.

Thanks for reading!
Stijn

Subscribe to our RSS feed

Hi there,
how can we help?

Got a project in mind?

Connect with us

Let's talk

Let's talk

Thanks, we'll be in touch soon!

Call us

Thanks, we've sent the link to your inbox

Invalid email address

Submit

Your download should start shortly!

Stay in Touch - Subscribe to Our Newsletter

Keep up to date with industry trends, events and the latest customer stories

Invalid email address

Submit

Great you’re on the list!