127 lines
4.2 KiB
Markdown
127 lines
4.2 KiB
Markdown
# PHPUnit Application Architecture Test
|
|
|
|
**Idea**: write architecture tests as well as feature and unit tests. Protect your architecture code style!
|
|
|
|
## Example
|
|
|
|
Don't use repositories in controllers use only in services classes. Take three layers "repositories", "services", "controllers" and add asserts on dependencies.
|
|
```php
|
|
$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);
|
|
```
|
|
|
|
|
|
## Installation
|
|
|
|
#### Install via composer
|
|
|
|
```bash
|
|
composer require --dev ta-tikoma/phpunit-architecture-test
|
|
```
|
|
|
|
#### Add trait to Test class
|
|
|
|
```php
|
|
abstract class TestCase extends BaseTestCase
|
|
{
|
|
use ArchitectureAsserts;
|
|
}
|
|
```
|
|
|
|
## Use
|
|
|
|
- Create test
|
|
- Make layers of application
|
|
- Add asserts
|
|
|
|
```php
|
|
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);
|
|
}
|
|
|
|
```
|
|
|
|
#### Run
|
|
```bash
|
|
./vendor/bin/phpunit
|
|
```
|
|
|
|
## Test files structure
|
|
|
|
- tests
|
|
- Architecture
|
|
- SomeTest.php
|
|
- Feature
|
|
- Unit
|
|
|
|
## How to build Layer
|
|
|
|
- `$this->layer()` take access to layer with all objects and filter for create your layer:
|
|
- leave objects in layer only:
|
|
- `->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
|
|
- remove objects from layer:
|
|
- `->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
|
|
- you can create multiple layers with split:
|
|
- `->split($closure)` by closure
|
|
- `->splitByNameRegex($closure)` by object name
|
|
|
|
|
|
## Asserts
|
|
|
|
### Dependencies
|
|
|
|
**Example:** 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).
|
|
|
|
### Methods
|
|
|
|
- `assertIncomingsFrom($A, $B)` Layer A must contains arguments with types from Layer B
|
|
- `assertIncomingsNotFrom($A, $B)` Layer A must not contains arguments with types from Layer B
|
|
- `assertOutgoingFrom($A, $B)` Layer A must contains methods return types from Layer B
|
|
- `assertOutgoingNotFrom($A, $B)` Layer A must not contains methods return types from Layer B
|
|
- `assertMethodSizeLessThan($A, $SIZE)` Layer A must not contains methods with size less than SIZE
|
|
|
|
### Properties
|
|
|
|
- `assertHasNotPublicProperties($A)` Objects in Layer A must not contains public properties
|
|
|
|
### Essence
|
|
|
|
You 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-function
|
|
- `assertNotOne($list, $check, $message)` - not one item of list must not passed tested by $check-function
|
|
- `assertAny($list, $check, $message)` - one or more item of list must not passed tested by $check-function
|
|
|
|
## Alternatives
|
|
- [Deptrac](https://github.com/qossmic/deptrac)
|
|
- [PHP Architecture Tester](https://github.com/carlosas/phpat)
|
|
- [PHPArch](https://github.com/j6s/phparch)
|
|
- [Arkitect](https://github.com/phparkitect/arkitect)
|
|
|
|
#### Advantages
|
|
- Dynamic creation of layers by regular expression (not need declare each module)
|
|
- Run along with the rest of tests from [phpunit](https://github.com/sebastianbergmann/phpunit)
|
|
- Asserts to method arguments and return types (for check dependent injection)
|
|
- Asserts to properties visibility
|