45 lines
1.9 KiB
Markdown
45 lines
1.9 KiB
Markdown
---
|
|
date: 2025-06-22
|
|
title: Consistency with architectural testing
|
|
permalink: /daily/2025/06/22/consistency-architectural-testing
|
|
---
|
|
|
|
Yesterday, I asked whether class names should include suffixes or be named a certain way in your application.
|
|
|
|
I said that [consistency is key][1].
|
|
|
|
But how do you enforce these rules to keep things consistent?
|
|
|
|
It could be done manually in a code review or pair programming session, but it would be better if it could be automated.
|
|
|
|
Similar to phpcs for code linting and automated tests that ensure functionality works as expected, architectural tests allow you to define and run your own architectural rules.
|
|
|
|
For example, I could write this to ensure Action classes don't have the `Action` suffix:
|
|
|
|
```php
|
|
function test_action_classes_are_not_suffixed(): Rule
|
|
{
|
|
return PHPat::rule()
|
|
->classes(Selector::inNamespace('App\Action'))
|
|
->shouldBeNamed(
|
|
fqcn: '/^(?!.*Action$).*$/',
|
|
regex: TRUE,
|
|
);
|
|
}
|
|
```
|
|
|
|
This is using PHPat - an extension for PHPStan - that finds all classes in an `App\Action` namespace and checks the class name matches the given format.
|
|
|
|
If the class name is incorrect, PHPStan will return an error:
|
|
|
|
> App\Action\DoesSomethingAction should be named matching the regex /^(?!.*Action$).*$/
|
|
|
|
I [created more examples][0] to ensure the classes are final, read-only and don't extend or implement anything.
|
|
|
|
PHPat has [an examples page][2] of potential use cases for architectural tests, and how to implement layered architectures or Model-View-Controller.
|
|
|
|
Pest PHP also has an architectural testing library so, if you use PHP, try both and see which works best for you.
|
|
|
|
[0]: https://code.oliverdavies.uk/opdavies/phpat-example/src/commit/cf07cec6d20bd4f6108736efdfbd2af549df2748/tests/Architecture/ArchitectureTest.php
|
|
[1]: /daily/2025/06/21/consistency-key
|
|
[2]: https://www.phpat.dev/examples
|