PHPUnit Application Architecture Test. For architecture tests
Idea: write architecture tests as well as feature and unit tests. Protect your architecture code style!
Don’t use repositories in controllers use only in services classes. Take three layers “repositories”, “services”, “controllers” and add asserts on dependencies.
$controllers = $this->layer()->leaveByNameStart('App\\Controllers');
$services = $this->layer()->leaveByNameStart('App\\Services');
$repositories = $this->layer()->leaveByNameStart('App\\Repositories');
$this->assertDoesNotDependOn($controllers, $repositories);
$this->assertDependOn($controllers, $services);
$this->assertDependOn($services, $repositories);
composer require --dev ta-tikoma/phpunit-architecture-test
abstract class TestCase extends BaseTestCase
{
use ArchitectureAsserts;
}
public function test_make_layer_from_namespace()
{
$app = $this->layer()->leaveByNameStart('PHPUnit\\Architecture');
$tests = $this->layer()->leaveByNameStart('tests');
$this->assertDoesNotDependOn($app, $tests);
$this->assertDependOn($tests, $app);
}
./vendor/bin/phpunit
$this->layer()
take access to layer with all objects and filter for create your layer:
->leave($closure)
by closure->leaveByPathStart($path)
by object path start->leaveByNameStart($name)
by object name start->leaveByNameRegex($name)
by object name regex->leaveByType($name)
by object type->exclude($closure)
by closure->excludeByPathStart($path)
by object path start->excludeByNameStart($name)
by object name start->excludeByNameRegex($name)
by object name regex->excludeByType($name)
by object type->split($closure)
by closure->splitByNameRegex($closure)
by object nameExample: Controllers don’t use Repositories only via Services
assertDependOn($A, $B)
Layer A must contains dependencies by layer B.assertDoesNotDependOn($A, $B)
Layer A (or layers in array A) must not contains dependencies by layer B (or layers in array B).assertIncomingsFrom($A, $B)
Layer A must contains arguments with types from Layer BassertIncomingsNotFrom($A, $B)
Layer A must not contains arguments with types from Layer BassertOutgoingFrom($A, $B)
Layer A must contains methods return types from Layer BassertOutgoingNotFrom($A, $B)
Layer A must not contains methods return types from Layer BassertMethodSizeLessThan($A, $SIZE)
Layer A must not contains methods with size less than SIZEassertHasNotPublicProperties($A)
Objects in Layer A must not contains public propertiesYou can use $layer->essence($path)
method for collect data from layer. For example get visibility of all properties in layer: $visibilities = $layer->essence('properties.*.visibility');
.
assertEach($list, $check, $message)
- each item of list must passed tested by $check-functionassertNotOne($list, $check, $message)
- not one item of list must not passed tested by $check-functionassertAny($list, $check, $message)
- one or more item of list must not passed tested by $check-function