Skip to content

Commit 84abbca

Browse files
authored
Doctrine annotations replaced by PHP attributes (#4395)
2 parents cf9f9f9 + a1776a8 commit 84abbca

File tree

13 files changed

+105
-137
lines changed

13 files changed

+105
-137
lines changed

README.md

Lines changed: 16 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ composer require --dev shopsys/http-smoke-testing
2121
```
2222

2323
This package internally uses [PHPUnit](https://phpunit.de/) to run the tests.
24-
That means that you need to setup your `phpunit.xml` properly.
24+
That means that you need to set up your `phpunit.xml` properly.
2525
Fortunately, Symfony comes with example configuration.
2626
Renaming the `phpunit.xml.dist` in your project root (or `app/phpunit.xml.dist` on Symfony 2) should be sufficient.
2727

@@ -42,7 +42,7 @@ php vendor/bin/phpunit tests/AppBundle/Smoke/SmokeTest.php
4242
**Warning: This package checks all routes by making real requests.**
4343
**It is important not to execute it on production data.**
4444
**You may unknowingly delete or modify your data or real requests on 3rd party services.**
45-
Even if you implement some way of protecting the application from side-effect (eg. database transaction wrapping) you should never execute tests on production data.
45+
Even if you implement some way of protecting the application from side effect (e.g., database transaction wrapping) you should never execute tests on production data.
4646

4747
### Example test class
4848

@@ -97,19 +97,19 @@ class SmokeTest extends HttpSmokeTestCase {
9797

9898
## Documentation
9999

100-
By default the test makes request to every route without using any authentication or providing any parameters and expects the response to have HTTP status code _200 OK_.
100+
By default, the test makes request to every route without using any authentication or providing any parameters and expects the response to have HTTP status code _200 OK_.
101101

102102
To change this behavior you must implement method `customizeRouteConfigs(RouteConfigCustomizer $routeConfigCustomizer)` in your test.
103103

104104
[`RouteConfigCustomizer`](./src/RouteConfigCustomizer.php) provides two methods for customizing individual route requests:
105105

106106
- `customize` accepts callback `function (RouteConfig $config, RouteInfo $info) {...}` as the only argument.
107107
This is called with each [`RouteConfig`](./src/RouteConfig.php) along with [`RouteInfo`](./src/RouteInfo.php) collected from your router.
108-
This method is useful when you want to define general rules for multiple routes (eg. skip all routes with name starting with underscore).
108+
This method is useful when you want to define general rules for multiple routes (e.g., skip all routes with name starting with underscore).
109109
- `customizeByRouteName` accepts a single route name or an array of route names as the first argument and same callback as `customize` as the second argument.
110110
This is called with each [`RouteConfig`](./src/RouteConfig.php) along with [`RouteInfo`](./src/RouteInfo.php) with matching route name.
111111
If matching route config is not found a [`RouteNameNotFoundException`](./src/Exception/RouteNameNotFoundException.php) is thrown.
112-
This method is useful when you want to define rules for specific routes (eg. logging in to some secured route).
112+
This method is useful when you want to define rules for specific routes (e.g., logging in to some secured route).
113113

114114
In your customizing callback you can call three methods on [`RouteConfig`](./src/RouteConfig.php) to change the tested behavior:
115115

@@ -122,33 +122,31 @@ In your customizing callback you can call three methods on [`RouteConfig`](./src
122122
or implement your own method using [`AuthInterface`](./src/Auth/AuthInterface.php).)
123123
- `setParameter` specifies value of a route parameter by name.
124124
- `addCallDuringTestExecution` adds a callback `function (RequestDataSet $requestDataSet, ContainerInterface $container) { ... }` to be called before test execution.
125-
(Useful for code that needs to access the same instance of container as the test method, eg. adding CSRF token as a route parameter)
126-
- `addExtraRequestDataSet` can be used to test more requests on the same route (eg. test a secured route as both logged in and anonymous user).
125+
(Useful for code that needs to access the same instance of container as the test method, e.g., adding CSRF token as a route parameter)
126+
- `addExtraRequestDataSet` can be used to test more requests on the same route (e.g., test a secured route as both logged in and anonymous user).
127127
Returns [`RequestDataSet`](./src/RequestDataSet.php) that you can use the same way as the result from `changeDefaultRequestDataSet`.
128128
All configured options will extend the values from default request data set (even when you change the default [`RequestDataSet`](./src/RequestDataSet.php) after you add the extra [`RequestDataSet`](./src/RequestDataSet.php)).
129129

130130
_Note: All three methods of [`RouteConfigCustomizer`](./src/RouteConfigCustomizer.php) accept `string $debugNote` as an argument._
131131
_It is useful for describing the reasons of your configuration change because it may help you with debugging when the test fails._
132132

133-
Additionally you can override these methods in your implementation of [`HttpSmokeTestCase`](./src/HttpSmokeTestCase.php) to further change the test behavior:
133+
Additionally, you can override these methods in your implementation of [`HttpSmokeTestCase`](./src/HttpSmokeTestCase.php) to further change the test behavior:
134134

135-
- `setUp` to change the way your kernel is booted (eg. boot it with different options).
135+
- `setUp` to change the way your kernel is booted (e.g., boot it with different options).
136136
- `getRouterAdapter` to change the object responsible for collecting routes from your application and generating urls.
137137
- `createRequest` if you have specific needs about the way `Request` is created from [`RequestDataSet`](./src/RequestDataSet.php).
138-
- `handleRequest` to customize handling `Request` in your application (eg. you can wrap it in database transaction to roll it back into original state).
138+
- `handleRequest` to customize handling `Request` in your application (e.g., you can wrap it in database transaction to roll it back into original state).
139139

140-
### Annotations
140+
### Attributes
141141

142-
To make smoke test configuration a little easier, you can use the annotations:
142+
To make smoke test configuration a little easier, you can use the PHP attributes:
143143

144144
#### DataSet
145145

146-
Used for setting expected status code based on provided paramteters.
146+
Used for setting expected status code based on provided parameters.
147147

148148
```
149-
@DataSet(statusCode=404, parameters={
150-
@Parameter(name="name", value="Batman")
151-
})
149+
#[DataSet(statusCode: 404, parameters: [new Parameter(name: 'name', value: 'Batman')])]
152150
```
153151

154152
- arguments:
@@ -160,7 +158,7 @@ Used for setting expected status code based on provided paramteters.
160158
Parameter defines value for specified parameter.
161159

162160
```
163-
@Parameter(name="name", value="Batman")
161+
new Parameter(name: 'name', value: 'Batman')
164162
```
165163

166164
- arguments:
@@ -172,7 +170,7 @@ Parameter defines value for specified parameter.
172170
Mark test as skipped
173171

174172
```
175-
@Skipped()
173+
#[Skipped]
176174
```
177175

178176
You can add them directly to your controller methods. See the example in [`Shopsys\HttpSmokeTesting\Test\TestController`](./src/Test/TestController.php).

composer.json

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@
3232
"symfony/framework-bundle": "^6.4",
3333
"symfony/http-foundation": "^6.4",
3434
"symfony/dependency-injection": "^6.4",
35-
"symfony/routing": "^6.4",
36-
"doctrine/annotations": "^1.10.4"
35+
"symfony/routing": "^6.4"
3736
}
3837
}

src/Annotation/DataSet.php

Lines changed: 0 additions & 21 deletions
This file was deleted.

src/Annotation/Parameter.php

Lines changed: 0 additions & 25 deletions
This file was deleted.

src/Annotation/Skipped.php

Lines changed: 0 additions & 15 deletions
This file was deleted.

src/Attribute/DataSet.php

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Shopsys\HttpSmokeTesting\Attribute;
6+
7+
use Attribute;
8+
9+
#[Attribute(Attribute::TARGET_METHOD | Attribute::IS_REPEATABLE)]
10+
class DataSet
11+
{
12+
/**
13+
* @param int $statusCode
14+
* @param \Shopsys\HttpSmokeTesting\Attribute\Parameter[] $parameters
15+
*/
16+
public function __construct(
17+
public int $statusCode = 200,
18+
public array $parameters = [],
19+
) {
20+
}
21+
}

src/Attribute/Parameter.php

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Shopsys\HttpSmokeTesting\Attribute;
6+
7+
class Parameter
8+
{
9+
/**
10+
* @param string $name
11+
* @param string $value
12+
*/
13+
public function __construct(
14+
public string $name,
15+
public string $value,
16+
) {
17+
}
18+
}

src/Attribute/Skipped.php

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Shopsys\HttpSmokeTesting\Attribute;
6+
7+
use Attribute;
8+
9+
#[Attribute(Attribute::TARGET_METHOD)]
10+
class Skipped
11+
{
12+
}

src/RequestDataSetGenerator.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@
55
namespace Shopsys\HttpSmokeTesting;
66

77
use Override;
8-
use Shopsys\HttpSmokeTesting\Annotation\DataSet;
9-
use Shopsys\HttpSmokeTesting\Annotation\Skipped;
8+
use Shopsys\HttpSmokeTesting\Attribute\DataSet;
9+
use Shopsys\HttpSmokeTesting\Attribute\Skipped;
1010

1111
class RequestDataSetGenerator implements RouteConfig
1212
{
@@ -52,7 +52,7 @@ private function getRequestDataSetForIteration(int $index): RequestDataSet
5252

5353
/**
5454
* @param \Shopsys\HttpSmokeTesting\RequestDataSet $requestDataSet
55-
* @param \Shopsys\HttpSmokeTesting\Annotation\DataSet $annotation
55+
* @param \Shopsys\HttpSmokeTesting\Attribute\DataSet $annotation
5656
*/
5757
private function fulfillRequestDataSetFromAnnotation(RequestDataSet $requestDataSet, DataSet $annotation): void
5858
{

src/RouterAdapter/SymfonyRouterAdapter.php

Lines changed: 17 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,11 @@
44

55
namespace Shopsys\HttpSmokeTesting\RouterAdapter;
66

7-
use Doctrine\Common\Annotations\AnnotationReader;
8-
use Doctrine\Common\Annotations\AnnotationRegistry;
97
use Override;
108
use ReflectionException;
119
use ReflectionMethod;
12-
use Shopsys\HttpSmokeTesting\Annotation\DataSet;
13-
use Shopsys\HttpSmokeTesting\Annotation\Skipped;
10+
use Shopsys\HttpSmokeTesting\Attribute\DataSet;
11+
use Shopsys\HttpSmokeTesting\Attribute\Skipped;
1412
use Shopsys\HttpSmokeTesting\RequestDataSet;
1513
use Shopsys\HttpSmokeTesting\RouteInfo;
1614
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
@@ -19,16 +17,11 @@
1917

2018
class SymfonyRouterAdapter implements RouterAdapterInterface
2119
{
22-
private AnnotationReader $annotationsReader;
23-
2420
/**
2521
* @param \Symfony\Component\Routing\RouterInterface $router
2622
*/
2723
public function __construct(private readonly RouterInterface $router)
2824
{
29-
AnnotationRegistry::registerLoader('class_exists');
30-
31-
$this->annotationsReader = new AnnotationReader();
3225
}
3326

3427
/**
@@ -40,7 +33,7 @@ public function getAllRouteInfo(): array
4033
$allRouteInfo = [];
4134

4235
foreach ($this->router->getRouteCollection() as $routeName => $route) {
43-
$allRouteInfo[] = new RouteInfo($routeName, $route, $this->extractAnnotationsForRoute($route));
36+
$allRouteInfo[] = new RouteInfo($routeName, $route, $this->extractAttributesForRoute($route));
4437
}
4538

4639
return $allRouteInfo;
@@ -50,10 +43,10 @@ public function getAllRouteInfo(): array
5043
* @param \Symfony\Component\Routing\Route $route
5144
* @return array
5245
*/
53-
private function extractAnnotationsForRoute(Route $route): array
46+
private function extractAttributesForRoute(Route $route): array
5447
{
5548
if ($route->hasDefault('_controller')) {
56-
return $this->extractAnnotationForController($route->getDefault('_controller'));
49+
return $this->extractAttributesForController($route->getDefault('_controller'));
5750
}
5851

5952
return [];
@@ -63,32 +56,34 @@ private function extractAnnotationsForRoute(Route $route): array
6356
* @param string $controller
6457
* @return array
6558
*/
66-
private function extractAnnotationForController(string $controller): array
59+
private function extractAttributesForController(string $controller): array
6760
{
6861
try {
6962
$reflectionMethod = new ReflectionMethod($controller);
7063
} catch (ReflectionException $e) {
7164
return [];
7265
}
7366

74-
return $this->getControllerMethodAnnotations($reflectionMethod);
67+
return $this->getControllerMethodAttributes($reflectionMethod);
7568
}
7669

7770
/**
7871
* @param \ReflectionMethod $reflectionMethod
79-
* @return array
72+
* @return array<\Shopsys\HttpSmokeTesting\Attribute\DataSet|\Shopsys\HttpSmokeTesting\Attribute\Skipped>
8073
*/
81-
private function getControllerMethodAnnotations(ReflectionMethod $reflectionMethod): array
74+
private function getControllerMethodAttributes(ReflectionMethod $reflectionMethod): array
8275
{
83-
$annotations = [];
76+
$attributes = [];
77+
78+
foreach ($reflectionMethod->getAttributes(DataSet::class) as $attribute) {
79+
$attributes[] = $attribute->newInstance();
80+
}
8481

85-
foreach ($this->annotationsReader->getMethodAnnotations($reflectionMethod) as $annotation) {
86-
if ($annotation instanceof DataSet || $annotation instanceof Skipped) {
87-
$annotations[] = $annotation;
88-
}
82+
foreach ($reflectionMethod->getAttributes(Skipped::class) as $attribute) {
83+
$attributes[] = $attribute->newInstance();
8984
}
9085

91-
return $annotations;
86+
return $attributes;
9287
}
9388

9489
/**

0 commit comments

Comments
 (0)