Automatically verify that team rules are met using Architectural Tests
Every team has rules and agreements on how to write and structure code. In the best case, these are documented, and yes we all know that developers don't like to read documentation, also every team has its unwritten rules. Some of these rules carry over across teams e.g. best practices, while others do not and are team-specific e.g. a personal preference or some historical reason.
So how do you make sure that everyone including new team members follow the team's style? We already established that it's hard to stick to the rules using a wiki. Pair programming and pull requests do help, but this doesn't scale well. This also leaves room for inconsistencies.
Instead of a human verifying if the rules are followed, we need a way to automate this process. While doing so, the agreed team rules are set in stone and cannot be ignored or misinterpreted.
Teams already rely on automated tests to test the functional requirements (and probably the non-functional requirements) of the application. So why not include test cases to test if your team rules are met?
As a solution, we can resort to Architectural Tests. Architectural Tests are comparable to unit tests and are focused on the architecture as a way to enforce team rules and agreements.
Automating this process gives the same benefits as other tests, it saves time and shortens the feedback loop. And one needs to be the bad guy while (repeatedly) commenting on someone else's code. As a result, this widens the pit of success. The same rules apply to every team member, this greatly improves the consistency within your codebase.
Some good candidates that qualify to write Architectural Tests are:
- Naming rules
- Dependency rules (Namespace and Types)
- Folder/namespace structure rules
- Attribute-based rules
To write architecture tests we use the ArchUnitNET package (a port from the popular ArchUnit package in the Java ecosystem). Using its FluentAPI rules (tests) can be created to assert the structure of a system. When a test fails, it provides a descriptive and clear error message, in which you can also include a reason.
Some practical examples:
While I was writing this Bit I also noticed Milan Jovanović created two videos (How To Create Better .NET Applications with Architecture Tests and How to Write Architecture Tests for the Clean Architecture) on Architectural Tests using a similar library NetArchTest. Both libraries serve the same purpose, and have a similar Fluent API, but are different in some small details e.g. in the way they assert the rules.
A little side note, there isn't a lot of documentation about both of these libraries and this will require some trial and error while writing your first architectural tests, at least this was the case for myself.
I appreciate it if you would support me if have you enjoyed this post and found it useful, thank you in advance.