{"id":322099,"date":"2021-04-26T09:00:56","date_gmt":"2021-04-26T09:00:56","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=322099"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=322099","title":{"rendered":"\u041f\u0440\u0430\u043a\u0442\u0438\u043a\u0438 \u043f\u0440\u0438 \u0440\u0430\u0431\u043e\u0442\u0435 \u0441 PHPUnit"},"content":{"rendered":"\n<div class=\"post__text post__text_v2\" id=\"post-content-body\">\n<figure class=\"float full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/b3a\/103\/8ee\/b3a1038eec0f3c5d90bd0b3724ce2c6b.png\" width=\"780\" height=\"439\"><figcaption><\/figcaption><\/figure>\n<p>\u041d\u0435 \u0441\u0435\u043a\u0440\u0435\u0442, \u0447\u0442\u043e \u0447\u0435\u043c \u0431\u043e\u043b\u044c\u0448\u0435 \u043f\u0440\u043e\u0435\u043a\u0442, \u0442\u0435\u043c \u0441 \u0431\u043e\u043b\u044c\u0448\u0438\u043c \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e\u043c \u043f\u0440\u043e\u0431\u043b\u0435\u043c \u043e\u043d \u0441\u0442\u0430\u043b\u043a\u0438\u0432\u0430\u0435\u0442\u0441\u044f \u0434\u0430\u0436\u0435 \u0432 \u0441\u0430\u043c\u044b\u0445 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0430\u0440\u043d\u044b\u0445 \u0430\u0441\u043f\u0435\u043a\u0442\u0430\u0445. \u0412 \u043f\u0440\u043e\u0434\u0443\u043a\u0442\u0435 <a href=\"https:\/\/www.plesk.com\/\">Plesk<\/a>, \u043d\u0430\u0434 \u043a\u043e\u0442\u043e\u0440\u044b\u043c \u044f \u0440\u0430\u0431\u043e\u0442\u0430\u044e, PHP \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043e\u0434\u043d\u0438\u043c \u0438\u0437 \u043e\u0441\u043d\u043e\u0432\u043d\u044b\u0445 \u044f\u0437\u044b\u043a\u043e\u0432, \u0438 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u043a\u043e\u0434\u0430 \u043d\u0430 \u043d\u0435\u043c \u043f\u0440\u0435\u0432\u044b\u0448\u0430\u0435\u0442 1 \u043c\u0438\u043b\u043b\u0438\u043e\u043d \u0441\u0442\u0440\u043e\u043a. \u0421\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0435\u043d\u043d\u043e, \u043c\u044b \u0430\u043a\u0442\u0438\u0432\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c <a href=\"https:\/\/phpunit.de\/\">PHPUnit<\/a> \u0434\u043b\u044f \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f. \u041a\u0440\u043e\u043c\u0435 \u0431\u043e\u043b\u044c\u0448\u043e\u0433\u043e \u043e\u0431\u044a\u0435\u043c\u0430 \u043a\u043e\u0434\u0430, \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0430 \u0434\u0432\u0443\u0445 \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c (Linux \u0438 Windows) \u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u043d\u044e\u0430\u043d\u0441\u044b, \u043a\u0430\u043a \u0438 \u0442\u043e\u0442 \u0444\u0430\u043a\u0442, \u0447\u0442\u043e \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442\u0441\u044f \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0431\u0440\u0430\u043d\u0447\u0435\u0439 \u0441 \u043f\u0440\u0438\u043b\u0438\u0447\u043d\u043e\u0439 \u0440\u0430\u0437\u043d\u0438\u0446\u0435\u0439 \u0432\u043e\u0437\u0440\u0430\u0441\u0442\u0430 (\u043a\u0440\u0443\u043f\u043d\u044b\u0435 \u0440\u0435\u043b\u0438\u0437\u044b), \u0430 \u0430\u043a\u0442\u0438\u0432\u043d\u043e \u0432\u043d\u043e\u0441\u044f\u0442 \u043f\u0440\u0430\u0432\u043a\u0438 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0434\u0435\u0441\u044f\u0442\u043a\u043e\u0432 \u0438\u043d\u0436\u0435\u043d\u0435\u0440\u043e\u0432. \u0412 \u0441\u0442\u0430\u0442\u044c\u0435 \u044f \u0445\u043e\u0447\u0443 \u043f\u043e\u0434\u0435\u043b\u0438\u0442\u044c\u0441\u044f \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u043c\u0438 \u043f\u0440\u0430\u043a\u0442\u0438\u043a\u0430\u043c\u0438, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043c\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c \u043f\u0440\u0438 \u0440\u0430\u0431\u043e\u0442\u0435 \u0441 PHPUnit. <\/p>\n<h2>\u0423\u043d\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044f<\/h2>\n<p>\u041f\u0435\u0440\u0432\u044b\u0439 \u043c\u043e\u043c\u0435\u043d\u0442, \u043d\u0430 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u043d\u0443\u0436\u043d\u043e \u043e\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c\u0441\u044f, \u2014 \u044d\u0442\u043e \u0443\u043d\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044f. \u0415\u0441\u043b\u0438 \u0432\u044b \u0435\u0434\u0438\u043d\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0439 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u043f\u0440\u043e\u0435\u043a\u0442\u0430, \u0442\u043e, \u043a\u043e\u043d\u0435\u0447\u043d\u043e, \u0434\u0435\u043b\u0430\u0442\u044c \u043c\u043e\u0436\u043d\u043e \u043a\u0430\u043a \u0443\u0433\u043e\u0434\u043d\u043e. \u041d\u043e \u0435\u0441\u043b\u0438 \u0432\u044b \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442\u0435 \u043d\u0430\u0434 \u043f\u0440\u043e\u0435\u043a\u0442\u043e\u043c \u043d\u0435 \u043e\u0434\u0438\u043d, \u0442\u043e \u043b\u0443\u0447\u0448\u0435 \u0434\u0435\u043b\u0430\u0442\u044c \u0432\u0441\u0435 \u0435\u0434\u0438\u043d\u043e\u043e\u0431\u0440\u0430\u0437\u043d\u043e \u0432 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0438\u0438 \u0441 \u043f\u0440\u0438\u043d\u044f\u0442\u044b\u043c\u0438 \u043f\u0440\u0430\u043a\u0442\u0438\u043a\u0430\u043c\u0438.<\/p>\n<p>\u0412 \u043c\u0438\u0440\u0435 PHP \u043f\u0440\u0438\u043d\u044f\u0442\u043e, \u0447\u0442\u043e\u0431\u044b \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u0443\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u043b\u0438\u0441\u044c \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e <code>composer install<\/code>, \u0430 \u043a\u043e\u043c\u0430\u043d\u0434\u0430 <code>composer test<\/code> \u043f\u0440\u043e\u0433\u043e\u043d\u044f\u043b\u0430 \u043d\u0430\u0431\u043e\u0440 \u0442\u0435\u0441\u0442\u043e\u0432. \u0412 \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u0435 PHPUnit \u044d\u0442\u043e \u043e\u0437\u043d\u0430\u0447\u0430\u0435\u0442 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0435. \u0417\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u044c \u043d\u0430 PHPUnit \u0434\u043e\u043b\u0436\u043d\u0430 \u043f\u0440\u0438\u0441\u0443\u0442\u0441\u0442\u0432\u043e\u0432\u0430\u0442\u044c \u0432 \u0440\u0430\u0437\u0434\u0435\u043b\u0435 &#171;require-dev&#187; \u0432 composer.json:<\/p>\n<pre><code class=\"json\">  \"require-dev\": {     ...     \"phpunit\/phpunit\": \"^9.5\",<\/code><\/pre>\n<p>\u0412 \u0440\u0430\u0437\u0434\u0435\u043b\u0435 scripts, \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0435\u043d\u043d\u043e, \u0434\u043e\u043b\u0436\u043d\u043e \u043f\u0440\u0438\u0441\u0443\u0442\u0441\u0442\u0432\u043e\u0432\u0430\u0442\u044c \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u0435 \u0434\u043b\u044f \u043a\u043e\u043c\u0430\u043d\u0434\u044b test:&nbsp;<\/p>\n<pre><code class=\"json\">  \"scripts\": {     ...     \"test\": \"phpunit\",<\/code><\/pre>\n<p>\u0420\u0430\u0437\u043b\u0438\u0447\u043d\u044b\u0435 \u043b\u0438\u043d\u0442\u0435\u0440\u044b \u0438 \u0441\u0442\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0435 \u0430\u043d\u0430\u043b\u0438\u0437\u0430\u0442\u043e\u0440\u044b, \u0435\u0441\u043b\u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0442\u0441\u044f, \u0442\u043e\u0436\u0435 \u0434\u043e\u043b\u0436\u043d\u044b \u043e\u043a\u0430\u0437\u0430\u0442\u044c\u0441\u044f \u0447\u0430\u0441\u0442\u044c\u044e \u044d\u0442\u043e\u0439 \u043a\u043e\u043c\u0430\u043d\u0434\u044b:<\/p>\n<pre><code class=\"json\">  \"scripts\": {     ...     \"test\": [       \"@phpcs\",       \"@phpstan\",       \"@psalm\",       \"@phpunit\"     ],<\/code><\/pre>\n<p>\u0414\u0430\u043b\u0435\u0435 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044e \u0434\u043b\u044f PHPUnit \u043d\u0443\u0436\u043d\u043e \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u0442\u044c \u0432 phpunit.xml.dist, \u0430 \u0444\u0430\u0439\u043b phpunit.xml \u0437\u0430\u043d\u0435\u0441\u0442\u0438 \u0432 .gitignore. \u0422\u0435\u043c \u0441\u0430\u043c\u044b\u043c \u043c\u044b \u0443\u043d\u0438\u0444\u0438\u0446\u0438\u0440\u0443\u0435\u043c \u043e\u043f\u0446\u0438\u0438 \u0437\u0430\u043f\u0443\u0441\u043a\u0430 PHPUnit, \u043e\u0441\u0442\u0430\u0432\u043b\u044f\u044f \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u043e\u0432\u0435\u0440\u0440\u0430\u0439\u0434\u0430 \u0434\u043b\u044f \u043a\u0430\u043a\u0438\u0445-\u0442\u043e \u044d\u043a\u0441\u043f\u0435\u0440\u0438\u043c\u0435\u043d\u0442\u043e\u0432. \u0420\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0439 \u043f\u043e\u0441\u043b\u0435 \u043a\u043b\u043e\u043d\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f, \u043f\u0440\u043e\u0433\u043e\u043d\u0430 <code>composer install<\/code> \u0438 \u0437\u0430\u043f\u0443\u0441\u043a\u0430 <code>composer test<\/code> \u043d\u0435 \u0434\u043e\u043b\u0436\u0435\u043d \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u0442\u044c \u043a\u0430\u043a\u0438\u0445-\u0442\u043e \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0445 \u043c\u0430\u043d\u0438\u043f\u0443\u043b\u044f\u0446\u0438\u0439. \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u0432 phpunit.xml.dist \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u043c, \u0433\u0434\u0435 \u0438\u0441\u043a\u0430\u0442\u044c \u0442\u0435\u0441\u0442\u044b, \u0447\u0442\u043e \u0438\u0441\u043a\u043b\u044e\u0447\u0430\u0442\u044c, \u043a\u0430\u043a\u0438\u0435 \u043e\u043f\u0446\u0438\u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0438 \u0442.\u043f.<\/p>\n<pre><code class=\"xml\">&lt;?xml version=\"1.0\"?&gt; &lt;phpunit   xmlns:xsi=\"http:\/\/www.w3.org\/2001\/XMLSchema-instance\"   bootstrap=\"common\/php\/tests\/bootstrap.php\"   executionOrder=\"random\"   ... &gt;   &lt;php&gt;     &lt;ini name=\"memory_limit\" value=\"-1\"\/&gt;     &lt;ini name=\"display_errors\" value=\"true\"\/&gt;     ...   &lt;\/php&gt;   &lt;testsuites&gt;     &lt;testsuite name=\"Plesk Common TestSuite\"&gt;       &lt;directory&gt;common\/php\/tests&lt;\/directory&gt;       &lt;exclude&gt;common\/php\/tests\/stubs&lt;\/exclude&gt;       ...     &lt;\/testsuite&gt;   &lt;\/testsuites&gt;   &lt;coverage includeUncoveredFiles=\"true\"&gt;     ...   &lt;\/coverage&gt; &lt;\/phpunit&gt; <\/code><\/pre>\n<p>\u041e\u0441\u0442\u0430\u043b\u043e\u0441\u044c \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u0442\u044c\u0441\u044f \u0441 \u0432\u0435\u0440\u0441\u0438\u0435\u0439 PHP, \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u043c\u0438 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u044f\u043c\u0438 \u0438 \u0437\u0430\u043d\u0435\u0441\u0442\u0438 \u044d\u0442\u0443 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u0432 composer.json:<\/p>\n<pre><code class=\"json\">  \"require\": {     \"php\": \"^7.4\",     \"ext-fileinfo\": \"*\",     \"ext-intl\": \"*\",     \"ext-json\": \"*\",     \"ext-mbstring\": \"*\",     ...   }<\/code><\/pre>\n<p>\u0411\u0430\u0437\u043e\u0432\u0430\u044f \u043f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u043a\u0430 \u0437\u0430\u043a\u043e\u043d\u0447\u0435\u043d\u0430. \u0421 \u043e\u0434\u043d\u043e\u0439 \u0441\u0442\u043e\u0440\u043e\u043d\u044b, \u0432\u0441\u0435 \u043f\u0440\u043e\u0441\u0442\u043e. \u0421 \u0434\u0440\u0443\u0433\u043e\u0439 \u0441\u0442\u043e\u0440\u043e\u043d\u044b, \u0440\u0435\u0433\u0443\u043b\u044f\u0440\u043d\u043e \u043f\u043e\u043f\u0430\u0434\u0430\u044e\u0442\u0441\u044f \u043f\u0440\u043e\u0435\u043a\u0442\u044b, \u0433\u0434\u0435 \u043a\u0430\u043a\u043e\u0439-\u0442\u043e \u0438\u0437 \u043c\u043e\u043c\u0435\u043d\u0442\u043e\u0432 \u0432\u044b\u0448\u0435 \u043e\u043a\u0430\u0437\u0430\u043b\u0441\u044f \u043f\u0440\u043e\u0438\u0433\u043d\u043e\u0440\u0438\u0440\u043e\u0432\u0430\u043d.<\/p>\n<h2>Docker<\/h2>\n<p>\u0410 \u043a\u0443\u0434\u0430 \u0436\u0435 \u0431\u0435\u0437 \u043d\u0435\u0433\u043e? \u0420\u0430\u0437 \u0443\u0436 \u043c\u044b \u0437\u0430\u0433\u043e\u0432\u043e\u0440\u0438\u043b\u0438 \u043e\u0431 \u0443\u043d\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438, \u0442\u043e \u043d\u0435\u043e\u0446\u0435\u043d\u0438\u043c\u0443\u044e \u043f\u043e\u043c\u043e\u0449\u044c \u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442 \u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 <a href=\"https:\/\/docs.docker.com\/language\/nodejs\/run-tests\/\">Docker\u2019\u0430<\/a>. \u0420\u0435\u0447\u044c \u043d\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u043e \u0435\u0433\u043e \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u0438 \u0434\u043b\u044f \u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u0442\u0435\u0441\u0442\u043e\u0432 \u0432 \u0440\u0430\u043c\u043a\u0430\u0445 CI-\u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0430. \u0414\u043b\u044f \u0442\u0435\u0445, \u043a\u0442\u043e \u043d\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442 PHP \u0432 \u0435\u0436\u0435\u0434\u043d\u0435\u0432\u043d\u043e\u0439 \u0440\u0430\u0431\u043e\u0442\u0435, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0434\u043b\u044f QA-\u0438\u043d\u0436\u0435\u043d\u0435\u0440\u0430, \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u0443\u0434\u043e\u0431\u043d\u044b\u043c \u0437\u0430\u043f\u0443\u0441\u043a \u0442\u0435\u0441\u0442\u043e\u0432 \u0432 Docker. \u0423\u0434\u043e\u0431\u043d\u044b\u043c \u0432 \u043f\u0435\u0440\u0432\u0443\u044e \u043e\u0447\u0435\u0440\u0435\u0434\u044c \u0442\u0435\u043c, \u0447\u0442\u043e \u0441\u043d\u0438\u043c\u0430\u0435\u0442 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u044c \u0432 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0435 \u043d\u0443\u0436\u043d\u043e\u0439 \u0432\u0435\u0440\u0441\u0438\u0438 PHP \u0441\u043e \u0432\u0441\u0435\u043c\u0438 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u044f\u043c\u0438 \u043d\u0430 \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u0443\u044e \u043c\u0430\u0448\u0438\u043d\u0443. \u041a\u0440\u043e\u043c\u0435 \u0442\u043e\u0433\u043e, \u044d\u0442\u043e \u0435\u0441\u043b\u0438 \u0432 \u0440\u0430\u0437\u043d\u044b\u0445 \u0440\u0435\u043b\u0438\u0437\u0430\u0445 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043b\u0430\u0441\u044c \u0440\u0430\u0437\u043d\u0430\u044f \u0432\u0435\u0440\u0441\u0438\u044f PHP, \u0442\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 Docker\u2019\u0430 \u043e\u0431\u043b\u0435\u0433\u0447\u0430\u0435\u0442 \u0431\u044d\u043a\u043f\u043e\u0440\u0442 \u043f\u0430\u0442\u0447\u0435\u0439 \u0438 \u043f\u0440\u043e\u0433\u043e\u043d \u0442\u0435\u0441\u0442\u043e\u0432 \u0432 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0445 \u0431\u0440\u0430\u043d\u0447\u0430\u0445.<\/p>\n<p>\u041e\u0440\u0433\u0430\u043d\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u0432\u0441\u0435 \u044d\u0442\u043e \u043c\u043e\u0436\u043d\u043e \u0432 \u0432\u0438\u0434\u0435 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e\u0433\u043e Dockerfile\u2019\u0430, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, Dockerfile-test \u0441\u043e \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u043d\u0438\u0435\u043c:<\/p>\n<pre><code>FROM php:7.4-cli  RUN apt-get update \\     &amp;&amp; apt-get install -y libxslt1-dev libzip-dev \\     &amp;&amp; docker-php-ext-install xsl \\     &amp;&amp; docker-php-ext-install intl \\     &amp;&amp; docker-php-ext-install zip \\     &amp;&amp; curl -sS https:\/\/getcomposer.org\/installer | php -- --install-dir=\/usr\/local\/bin --filename=composer<\/code><\/pre>\n<p>\u0414\u0430\u043b\u0435\u0435 \u0441\u043e\u0437\u0434\u0430\u0435\u043c \u0438\u043d\u0441\u0442\u0440\u0443\u043a\u0446\u0438\u0438 \u0434\u043b\u044f Docker Compose (\u0432 \u043c\u043e\u0435\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u0432 \u0444\u0430\u0439\u043b\u0435 docker-compose.test.yml):<\/p>\n<pre><code>version: '3' services:   tests:     build:       context: .       dockerfile: Dockerfile-test     command: bash -c \"cd \/opt\/plesk &amp;&amp; composer install &amp;&amp; composer test\"     volumes:       - .:\/opt\/plesk<\/code><\/pre>\n<p>\u0412 \u0438\u0442\u043e\u0433\u0435 \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442\u0441\u044f \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u0438\u0434\u0438\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0439 \u0437\u0430\u043f\u0443\u0441\u043a \u0442\u0435\u0441\u0442\u043e\u0432:<\/p>\n<pre><code>docker-compose -f docker-compose.test.yml run tests<\/code><\/pre>\n<p>\u0420\u0430\u0437\u043d\u0438\u0446\u0430 \u043f\u043e \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u043c\u0435\u0436\u0434\u0443 \u043c\u0435\u0436\u0434\u0443 \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u044b\u043c \u043f\u0440\u043e\u0433\u043e\u043d\u043e\u043c \u0438 \u043f\u0440\u043e\u0433\u043e\u043d\u043e\u043c \u0432 Docker\u2019\u0435 \u0432 \u043c\u043e\u0435\u043c \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u0441\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 3 \u0440\u0430\u0437\u0430. \u0422\u043e \u0435\u0441\u0442\u044c \u043f\u0440\u0438\u043c\u0435\u0440\u043d\u043e 30 \u0441\u0435\u043a\u0443\u043d\u0434 \u043f\u0440\u043e\u0442\u0438\u0432 10 \u0441\u0435\u043a\u0443\u043d\u0434 \u0434\u043b\u044f \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u043f\u0440\u043e\u0433\u043e\u043d\u0430.<\/p>\n<h2>PhpStorm<\/h2>\n<p>\u0414\u043b\u044f \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u044f PHP \u043a\u043e\u0434\u0430 \u043e\u0431\u044b\u0447\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f <a href=\"https:\/\/www.jetbrains.com\/phpstorm\/\">PhpStorm<\/a>. \u0415\u0441\u0442\u044c \u0432 \u043d\u0435\u043c \u0438 \u0443\u0434\u043e\u0431\u043d\u044b\u0435 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u044b \u043f\u043e \u0440\u0430\u0431\u043e\u0442\u0435 \u0441 PHPUnit.<\/p>\n<p>\u0412\u043e-\u043f\u0435\u0440\u0432\u044b\u0445, \u044d\u0442\u043e \u0437\u0430\u043f\u0443\u0441\u043a \u0442\u0435\u0441\u0442\u043e\u0432, \u0432\u044b\u0431\u0438\u0440\u0430\u044f \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044e \u0438\u0437 \u043c\u0435\u043d\u044e Run (\u0438\u043b\u0438 \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u043d\u043e\u0433\u043e \u043c\u0435\u043d\u044e) phpunit.xml.dist \u0438\u043b\u0438 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u044e, \u0433\u0434\u0435 \u0440\u0430\u0441\u043f\u043e\u043b\u043e\u0436\u0435\u043d\u044b \u0442\u0435\u0441\u0442\u044b. \u041d\u0430\u043a\u043b\u0430\u0434\u043d\u044b\u0435 \u0440\u0430\u0441\u0445\u043e\u0434\u044b \u043d\u0430 \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u0443\u044e \u0432\u0438\u0437\u0443\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e \u0432 PhpStorm \u043d\u0430 \u043c\u043e\u0435\u0439 \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u043e\u0439 \u043c\u0430\u0448\u0438\u043d\u0435 \u0432 \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u043e\u043c \u043f\u0440\u043e\u0435\u043a\u0442\u0435 (~4500 \u0442\u0435\u0441\u0442\u043e\u0432.) \u043f\u043b\u0430\u0432\u0430\u044e\u0442 \u0432 \u0434\u0438\u0430\u043f\u0430\u0437\u043e\u043d\u0435 10-30%, \u043d\u043e \u0432 \u0430\u0431\u0441\u043e\u043b\u044e\u0442\u043d\u044b\u0445 \u0446\u0438\u0444\u0440\u0430\u0445 \u2014 \u044d\u0442\u043e 13 \u0441\u0435\u043a\u0443\u043d\u0434, \u043f\u0440\u043e\u0442\u0438\u0432 10 \u0441\u0435\u043a\u0443\u043d\u0434 \u043f\u0440\u0438 \u0437\u0430\u043f\u0443\u0441\u043a\u0435 \u0432 \u0442\u0435\u0440\u043c\u0438\u043d\u0430\u043b\u0435, \u0447\u0442\u043e \u0441\u043e\u0432\u0435\u0440\u0448\u0435\u043d\u043d\u043e \u043d\u0435\u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0435\u043d\u043d\u043e.<\/p>\n<p>\u0412\u0442\u043e\u0440\u043e\u0439 \u0443\u0434\u043e\u0431\u043d\u044b\u0439 \u043c\u043e\u043c\u0435\u043d\u0442 \u043f\u0440\u0438 \u0438\u043d\u0442\u0435\u043d\u0441\u0438\u0432\u043d\u043e\u0439 \u0440\u0430\u0431\u043e\u0442\u0435 \u0441 \u0442\u0435\u0441\u0442\u0430\u043c\u0438 \u0438 \u0438\u0445 \u0430\u043a\u0442\u0438\u0432\u043d\u043e\u043c \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u0438 \u2014 \u044d\u0442\u043e \u0440\u0435\u0436\u0438\u043c \u201c\u043d\u0430\u0431\u043b\u044e\u0434\u0435\u043d\u0438\u044f\u201d. \u0412\u043a\u043b\u044e\u0447\u0430\u0435\u043c \u0435\u0433\u043e \u0432 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0435\u0439 \u043f\u0430\u043d\u0435\u043b\u0438:<\/p>\n<figure class=\"\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/00b\/021\/0b2\/00b0210b2957ed794ad325254155a88b.png\" width=\"200\" height=\"191\"><figcaption><\/figcaption><\/figure>\n<p>\u041f\u043e\u0441\u043b\u0435 \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0431\u0443\u0434\u0435\u0442 \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442\u044c \u043f\u0435\u0440\u0435\u0437\u0430\u043f\u0443\u0441\u043a \u0442\u0435\u0441\u0442\u043e\u0432, \u0430 \u043f\u043e \u0435\u0433\u043e \u043e\u043a\u043e\u043d\u0447\u0430\u043d\u0438\u044e \u2014 \u0432\u0441\u043f\u043b\u044b\u0432\u0430\u0442\u044c \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0435\u0435 \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u0435 \u043e \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0430\u0445 \u043f\u0440\u043e\u0445\u043e\u0436\u0434\u0435\u043d\u0438\u044f.<\/p>\n<p>\u041f\u0440\u0438 \u043d\u0430\u043b\u0438\u0447\u0438\u0438 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u0438\u0445 \u043c\u043e\u043d\u0438\u0442\u043e\u0440\u043e\u0432, \u043e\u0447\u0435\u043d\u044c \u0443\u0434\u043e\u0431\u043d\u043e \u0432\u044b\u043d\u0435\u0441\u0442\u0438 \u043e\u043a\u043d\u043e \u0441 \u0442\u0435\u0441\u0442\u0430\u043c\u0438 \u043d\u0430 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0439 \u043c\u043e\u043d\u0438\u0442\u043e\u0440 \u0438 \u0432\u043a\u043b\u044e\u0447\u0438\u0442\u044c \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0439 \u043f\u0435\u0440\u0435\u0437\u0430\u043f\u0443\u0441\u043a. \u0410 \u0447\u0442\u043e\u0431\u044b \u0442\u0435\u0441\u0442\u044b \u043d\u0435 \u043f\u0435\u0440\u0435\u0437\u0430\u043f\u0443\u0441\u043a\u0430\u043b\u0438\u0441\u044c \u0441\u043b\u0438\u0448\u043a\u043e\u043c \u0447\u0430\u0441\u0442\u043e, \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u0438\u0433\u0440\u0430\u0442\u044c\u0441\u044f \u0441 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u043e\u0439 \u0437\u0430\u0434\u0435\u0440\u0436\u043a\u0438 \u0437\u0430\u043f\u0443\u0441\u043a\u0430:<\/p>\n<figure class=\"\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/b1c\/980\/936\/b1c980936fcf799165adb27fcc18e43a.png\" width=\"400\" height=\"287\"><figcaption><\/figcaption><\/figure>\n<h2>\u0412\u043d\u0435\u0448\u043d\u0435\u0435 \u043d\u0430\u0431\u043b\u044e\u0434\u0435\u043d\u0438\u0435 \u0437\u0430 \u0442\u0435\u0441\u0442\u0430\u043c\u0438<\/h2>\n<p>\u0424\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b \u201c\u043d\u0430\u0431\u043b\u044e\u0434\u0435\u043d\u0438\u044f\u201d \u0437\u0430 \u0442\u0435\u0441\u0442\u0430\u043c\u0438 \u0432 PhpStorm \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442 \u0443\u0436\u0435 \u0433\u043e\u0434\u0430 3. \u0414\u043e \u044d\u0442\u043e\u0433\u043e \u0437\u0430\u0434\u0430\u0447\u0430 \u0440\u0435\u0448\u0430\u043b\u0430\u0441\u044c \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0432\u043d\u0435\u0448\u043d\u0435\u0433\u043e \u201c\u043d\u0430\u0431\u043b\u044e\u0434\u0430\u0442\u0435\u043b\u044f\u201d. \u041e\u0434\u043d\u0430\u043a\u043e \u0438 \u0441\u0435\u0439\u0447\u0430\u0441 \u043f\u043e \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043d\u044b\u043c \u043f\u0440\u0438\u0447\u0438\u043d\u0430\u043c \u0432\u043d\u0435\u0448\u043d\u0438\u0439 \u201c\u043d\u0430\u0431\u043b\u044e\u0434\u0430\u0442\u0435\u043b\u044c\u201d \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u043f\u043e\u043b\u0435\u0437\u0435\u043d (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0432\u044b \u043f\u0440\u0430\u0432\u0438\u0442\u0435 \u043a\u043e\u0434 \u0432 vim\u2019\u0435 \u0438\u043b\u0438 VSCode).&nbsp;<\/p>\n<p>\u041d\u0430\u0438\u0431\u043e\u043b\u0435\u0435 \u043f\u043e\u043f\u0443\u043b\u044f\u0440\u043d\u044b\u0439 \u0438 \u0436\u0438\u0432\u043e\u0439 \u043f\u0440\u043e\u0435\u043a\u0442 \u043f\u043e \u0434\u0430\u043d\u043d\u043e\u0439 \u0442\u0435\u043c\u0435 \u044d\u0442\u043e <a href=\"https:\/\/github.com\/spatie\/phpunit-watcher\">phpunit-watcher<\/a>. \u0414\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u0435\u0433\u043e \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e composer \u0438 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u043c phpunit-watcher.yml \u043f\u0440\u0438\u043c\u0435\u0440\u043d\u043e \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0433\u043e \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u043d\u0438\u044f:<\/p>\n<pre><code>watch:   directories:     - common\/php     - ...   fileMask: '*.php' phpunit:   binaryPath: common\/php\/plib\/vendor\/bin\/phpunit   arguments: '--stop-on-failure'<\/code><\/pre>\n<p>\u0422\u0430\u043a\u0436\u0435 \u0432 composer.json \u0432 \u0440\u0430\u0437\u0434\u0435\u043b scripts \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u0435\u0449\u0435 \u043e\u0434\u043d\u0443 \u043a\u043e\u043c\u0430\u043d\u0434\u0443:<\/p>\n<pre><code>\"scripts\": {     ...     \"test:watch\": \"phpunit-watcher watch\",     ...<\/code><\/pre>\n<p>\u0422\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c, \u0434\u043b\u044f \u0442\u043e\u0433\u043e, \u0447\u0442\u043e\u0431\u044b \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c \u0442\u0435\u0441\u0442\u044b \u043f\u043e\u0434 \u201c\u043d\u0430\u0431\u043b\u044e\u0434\u0435\u043d\u0438\u0435\u043c\u201d, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u043a\u043e\u043c\u0430\u043d\u0434\u0430 <code>composer test:watch<\/code> \u041e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u043c \u0435\u0435 \u0436\u0438\u0442\u044c \u0432 \u043e\u043a\u043e\u0448\u043a\u043e \u0442\u0435\u0440\u043c\u0438\u043d\u0430\u043b\u0430 \u043d\u0430 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0439 \u043c\u043e\u043d\u0438\u0442\u043e\u0440 \u0438 \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u0443\u0434\u043e\u0431\u0441\u0442\u0432\u043e \u043d\u0430\u0431\u043b\u044e\u0434\u0435\u043d\u0438\u044f, \u0430\u043d\u0430\u043b\u043e\u0433\u0438\u0447\u043d\u043e\u0435 PhpStorm\u2019\u0443.<\/p>\n<h2>\u041a\u043e\u043d\u0442\u0440\u043e\u043b\u044c \u0443\u0440\u043e\u0432\u043d\u044f \u043f\u043e\u043a\u0440\u044b\u0442\u0438\u044f<\/h2>\n<p>\u041f\u0440\u0438 \u0440\u043e\u0441\u0442\u0435 \u043a\u043e\u0434\u043e\u0432\u043e\u0439 \u0431\u0430\u0437\u044b \u0438 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u0430 \u0442\u0435\u0441\u0442\u043e\u0432 \u0432\u043e\u0437\u043d\u0438\u043a\u0430\u0435\u0442 \u0436\u0435\u043b\u0430\u043d\u0438\u0435 \u0443\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0442\u044c code coverage \u0445\u043e\u0442\u044f \u0431\u044b \u043d\u0430 \u0443\u0436\u0435 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0449\u0435\u043c \u0443\u0440\u043e\u0432\u043d\u0435 (\u0430 \u0432 \u0438\u0434\u0435\u0430\u043b\u0435 \u2014 \u0443\u0432\u0435\u043b\u0438\u0447\u0438\u0432\u0430\u0442\u044c \u0435\u0433\u043e). \u041c\u043e\u0436\u043d\u043e \u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0443\u0433\u043e\u0434\u043d\u043e \u043f\u044b\u0442\u0430\u0442\u044c\u0441\u044f \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u044d\u0442\u043e \u0440\u0443\u043a\u0430\u043c\u0438 (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0441\u0438\u043b\u0430\u043c\u0438 \u043a\u0430\u043a\u043e\u0433\u043e-\u0442\u043e \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u043e\u0433\u043e \u0438\u043d\u0436\u0435\u043d\u0435\u0440\u0430), \u0430 \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u0440\u0443\u0447\u0438\u0442\u044c \u044d\u0442\u0443 \u0437\u0430\u0434\u0430\u0447\u0443 \u0440\u043e\u0431\u043e\u0442\u0443. <\/p>\n<p>\u0421\u0445\u0435\u043c\u0430 \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c. \u0421\u043d\u0430\u0447\u0430\u043b\u0430 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u043c \u043f\u043e\u0434\u0441\u0447\u0435\u0442 code coverage, \u0441\u043c\u043e\u0442\u0440\u0438\u043c \u043f\u0440\u043e\u0446\u0435\u043d\u0442 \u043f\u043e\u043a\u0440\u044b\u0442\u0438\u044f \u0438 \u0443\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u043c \u0435\u0433\u043e \u043a\u0430\u043a \u043e\u0442\u043f\u0440\u0430\u0432\u043d\u0443\u044e \u0442\u043e\u0447\u043a\u0443. \u0414\u0430\u043b\u0435\u0435 \u0441\u043e\u0437\u0434\u0430\u0435\u043c \u0441\u043a\u0440\u0438\u043f\u0442, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0431\u0443\u0434\u0435\u0442 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0442\u044c \u043d\u0435\u043d\u0443\u043b\u0435\u0432\u043e\u0439 \u043a\u043e\u0434 \u0432\u043e\u0437\u0432\u0440\u0430\u0442\u0430 (\u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u044f \u043f\u0430\u0434\u0435\u043d\u0438\u0435), \u0435\u0441\u043b\u0438 \u0442\u0435\u043a\u0443\u0449\u0438\u0439 \u043f\u0440\u043e\u0446\u0435\u043d\u0442 code coverage \u0441\u0442\u0430\u043b \u043d\u0438\u0436\u0435 \u043e\u0442\u043f\u0440\u0430\u0432\u043d\u043e\u0439 \u0442\u043e\u0447\u043a\u0438. \u0414\u0430\u043d\u043d\u044b\u0439 \u0441\u043a\u0440\u0438\u043f\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0432 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0430\u0445 \u043d\u0430 pull request\u2019\u0430\u0445, \u0442\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c \u043d\u0435 \u0434\u0430\u0432\u0430\u044f \u0437\u0430\u043c\u0435\u0440\u0436\u0438\u0442\u044c \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f, \u0435\u0441\u043b\u0438 \u043f\u0440\u043e\u0446\u0435\u043d\u0442 code coverage \u0443\u043f\u0430\u043b. \u0414\u043e\u0431\u0430\u0432\u0438\u043b \u043d\u043e\u0432\u044b\u0439 \u043a\u043e\u0434? \u041d\u0443\u0436\u043d\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0442\u0435\u0441\u0442\u044b. \u0421 \u0440\u043e\u0431\u043e\u0442\u043e\u043c-\u0440\u0435\u0432\u044c\u044e\u0432\u0435\u0440\u043e\u043c \u0443\u0436\u0435 \u043d\u0435\u043b\u044c\u0437\u044f \u0434\u043e\u0433\u043e\u0432\u043e\u0440\u0438\u0442\u044c\u0441\u044f, \u043c\u043e\u043b, \u044f \u0447\u0443\u0442\u044c \u043f\u043e\u0437\u0436\u0435 \u0438\u0445 \u0434\u043e\u0431\u0430\u0432\u043b\u044e. \u041e\u043d \u0431\u0435\u0441\u043f\u0440\u0438\u0441\u0442\u0440\u0430\u0441\u0442\u043d\u043e \u043f\u043e\u0441\u0442\u0430\u0432\u0438\u0442 \u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u043a\u0443.<\/p>\n<p>\u0414\u043b\u044f \u043f\u043e\u0434\u0441\u0447\u0435\u0442\u0430 code coverage \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u0435 <a href=\"https:\/\/xdebug.org\/\">Xdebug<\/a>. \u041d\u0430 \u0434\u0430\u043d\u043d\u044b\u0439 \u043c\u043e\u043c\u0435\u043d\u0442, \u043d\u0430 \u0432\u0435\u0440\u0441\u0438\u0438 3.0 \u043d\u0430 \u0432\u0441\u0435\u0445 \u043f\u0440\u043e\u0435\u043a\u0442\u0430\u0445, \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u0441\u043c\u043e\u0442\u0440\u0435\u043b, \u0434\u0435\u043b\u043e \u0437\u0430\u043a\u0430\u043d\u0447\u0438\u0432\u0430\u0435\u0442\u0441\u044f segfault\u2019\u043e\u043c (\u0435\u0441\u0442\u044c \u043a\u0430\u043a \u201c\u043f\u043b\u0430\u0432\u0430\u044e\u0449\u0438\u0435\u201d \u0431\u0430\u0433\u0438, \u0442\u0430\u043a \u0438 \u0441\u0442\u0430\u0431\u0438\u043b\u044c\u043d\u043e \u043f\u043e\u0432\u0442\u043e\u0440\u044f\u0435\u043c\u044b\u0435 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u044b), \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u043f\u0440\u043e\u0434\u043e\u043b\u0436\u0430\u0435\u043c \u043f\u043e\u043a\u0430 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c 2.9.0. \u041f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u044f \u0441 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430\u043c\u0438 \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e (xdebug.mode=develop) \u0434\u0430\u0436\u0435 \u0431\u0435\u0437 \u043f\u043e\u0434\u0441\u0447\u0435\u0442\u0430 code coverage \u043f\u0440\u0438\u0432\u043e\u0434\u0438\u0442 \u043a 2-3 \u043a\u0440\u0430\u0442\u043d\u043e\u043c\u0443 \u0437\u0430\u043c\u0435\u0434\u043b\u0435\u043d\u0438\u044e \u043f\u0440\u043e\u0433\u043e\u043d\u0430 \u0442\u0435\u0441\u0442\u043e\u0432. \u0412 \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u0441 ~4500 \u0442\u0435\u0441\u0442\u0430\u043c\u0438 \u043d\u0430 \u043c\u043e\u0435\u0439 \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u043e\u0439 \u043c\u0430\u0448\u0438\u043d\u0435 \u043f\u0440\u043e\u0446\u0435\u0441\u0441 \u0437\u0430\u043c\u0435\u0434\u043b\u044f\u0435\u0442\u0441\u044f \u0441 10 \u0441\u0435\u043a\u0443\u043d\u0434 \u0434\u043e 27 \u0441\u0435\u043a\u0443\u043d\u0434. \u041f\u043e\u043a\u0430 \u0435\u0449\u0435 \u043d\u0435 \u0441\u0438\u043b\u044c\u043d\u043e \u043a\u0440\u0438\u0442\u0438\u0447\u043d\u043e, \u043d\u043e \u0443\u0436\u0435 \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u0437\u0430\u043c\u0435\u0442\u043d\u043e. \u0415\u0441\u043b\u0438 \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c \u043f\u0440\u043e\u0433\u043e\u043d \u0442\u0435\u0441\u0442\u043e\u0432 \u0432\u043c\u0435\u0441\u0442\u0435 \u0441 \u043f\u043e\u0434\u0441\u0447\u0435\u0442\u043e\u043c code coverage, \u0442\u043e \u043e\u043d \u0437\u0430\u0439\u043c\u0435\u0442 \u0432 \u043c\u043e\u0435\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u0431\u043e\u043b\u044c\u0448\u0435 30 \u043c\u0438\u043d\u0443\u0442. \u0415\u0441\u043b\u0438 \u043f\u0440\u043e\u0446\u0435\u043d\u0442 code coverage \u0443\u043f\u0430\u043b, \u0432\u044b \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u0442\u0435 \u043d\u043e\u0432\u044b\u0435 \u0442\u0435\u0441\u0442\u044b \u0438 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0440\u0430\u0437 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442\u0435 \u0438\u0445 \u043f\u0440\u043e\u0433\u043e\u043d, \u0442\u043e \u0436\u0434\u0430\u0442\u044c \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0440\u0430\u0437 \u043f\u043e 30 \u043c\u0438\u043d\u0443\u0442 \u2014 \u044d\u0442\u043e \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u0434\u043e\u043b\u0433\u043e.<\/p>\n<p>\u0410\u043d\u0430\u043b\u0438\u0437 \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442, \u0447\u0442\u043e \u0431\u043e\u043b\u044c\u0448\u0435 \u0432\u0441\u0435\u0433\u043e \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u0434\u043b\u044f \u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u0438 \u043e\u0442\u0447\u0435\u0442\u0430 \u0432 HTML. \u0422\u0430\u043a \u043a\u0430\u043a \u0441\u0430\u043c \u043e\u0442\u0447\u0435\u0442 \u043d\u0430\u0441 \u043d\u0435 \u043e\u0441\u043e\u0431\u043e \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u0443\u0435\u0442, \u0442\u043e \u043c\u043e\u0436\u043d\u043e \u0432\u043e\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u043e\u043f\u0446\u0438\u0435\u0439 &#8212;coverage-php, \u0430 \u0434\u0430\u043b\u0435\u0435 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u043d\u044b\u0439 \u0444\u0430\u0439\u043b \u043f\u0440\u043e\u0430\u043d\u0430\u043b\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u043c \u0441\u043a\u0440\u0438\u043f\u0442\u043e\u043c. \u0412 \u0438\u0442\u043e\u0433\u0435 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u0442\u0435\u043a\u0443\u0449\u0435\u0433\u043e \u043f\u0440\u043e\u0446\u0435\u043d\u0442\u0430 code coverage \u0438\u0437 30 \u043c\u0438\u043d\u0443\u0442 \u043f\u0440\u0435\u0432\u0440\u0430\u0449\u0430\u0435\u0442\u0441\u044f \u0432 2 \u043c\u0438\u043d\u0443\u0442\u044b \u043d\u0430 \u043f\u0440\u043e\u0433\u043e\u043d \u0442\u0435\u0441\u0442\u043e\u0432 \u0438 \u0435\u0449\u0435 \u043f\u0440\u0438\u043c\u0435\u0440\u043d\u043e 2,5 \u043c\u0438\u043d\u0443\u0442\u044b \u043d\u0430 \u0430\u043d\u0430\u043b\u0438\u0437 \u0440\u0435\u043f\u043e\u0440\u0442\u0430 (\u043d\u0430\u043f\u043e\u043c\u043d\u044e, \u0447\u0442\u043e \u043f\u0440\u043e\u0435\u043a\u0442 \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u0431\u043e\u043b\u044c\u0448\u043e\u0439, \u0438 \u0444\u0430\u0439\u043b \u0437\u0430\u043d\u0438\u043c\u0430\u0435\u0442 \u0431\u043e\u043b\u0435\u0435 60 \u041c\u0431). \u0415\u0441\u0442\u044c \u0435\u0449\u0435 \u043f\u043e\u043b\u0435 \u0434\u043b\u044f \u043e\u043f\u0442\u0438\u043c\u0438\u0437\u0430\u0446\u0438\u0438, \u043d\u043e \u0442\u0435\u043a\u0443\u0449\u0438\u0439 \u0432\u0430\u0440\u0438\u0430\u043d\u0442 \u0443\u0436\u0435 \u0443\u0441\u0442\u0440\u0430\u0438\u0432\u0430\u0435\u0442. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0441\u043e\u043a\u0440\u0430\u0442\u0438\u0442\u044c \u043f\u0435\u0440\u0432\u0443\u044e \u0444\u0430\u0437\u0443 \u0441 2 \u043c\u0438\u043d\u0443\u0442 \u0434\u043e 1 \u043c\u0438\u043d\u0443\u0442\u044b \u043c\u043e\u0436\u043d\u043e \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e <a href=\"https:\/\/github.com\/krakjoe\/pcov\">pcov<\/a>.<\/p>\n<p>\u0412 phpunit.dist.xml \u043d\u0443\u0436\u043d\u043e \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u0442\u044c\u0441\u044f \u0441 \u0441\u0435\u043a\u0446\u0438\u0435\u0439 coverage. \u0422\u0430\u043a\u0436\u0435 \u0432\u0430\u0436\u043d\u043e \u0443\u043a\u0430\u0437\u0430\u0442\u044c \u043e\u043f\u0446\u0438\u044e includeUncoveredFiles, \u043f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e \u043f\u0440\u043e\u0446\u0435\u043d\u0442 \u043f\u043e\u043a\u0440\u044b\u0442\u0438\u044f \u043d\u0443\u0436\u043d\u043e \u0441\u0447\u0438\u0442\u0430\u0442\u044c \u043e\u0442 \u0432\u0441\u0435\u0445 \u0444\u0430\u0439\u043b\u043e\u0432, \u0430 \u043d\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u0442\u0435\u0445, \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u201c\u043a\u0430\u0441\u0430\u043b\u0438\u0441\u044c\u201d \u0442\u0435\u0441\u0442\u044b.<\/p>\n<pre><code class=\"xml\"> &lt;coverage includeUncoveredFiles=\"true\"&gt;     &lt;include&gt;       &lt;directory suffix=\".php\"&gt;common\/php&lt;\/directory&gt;       ...     &lt;\/include&gt;     &lt;exclude&gt;       &lt;directory&gt;common\/php\/plib\/locales&lt;\/directory&gt;       &lt;directory&gt;common\/php\/plib\/vendor&lt;\/directory&gt;       &lt;directory&gt;common\/php\/tests&lt;\/directory&gt;       ...     &lt;\/exclude&gt;   &lt;\/coverage&gt;<\/code><\/pre>\n<p>\u0412 composer.json \u0444\u043e\u0440\u043c\u0438\u0440\u0443\u0435\u043c \u043a\u043e\u043c\u0430\u043d\u0434\u0443 \u0434\u043b\u044f \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u0441 \u0443\u0447\u0435\u0442\u043e\u043c \u0432\u0441\u0435\u0433\u043e \u0432\u044b\u0448\u0435\u0441\u043a\u0430\u0437\u0430\u043d\u043d\u043e\u0433\u043e:<\/p>\n<pre><code class=\"json\"> \"scripts\": {     ...     \"test-coverage-threshold\": [       \"@php -dzend_extension=xdebug.so -dxdebug.mode=coverage common\/php\/plib\/vendor\/bin\/phpunit --coverage-php .phpunit.coverage.php\",       \"@php -dzend_extension=xdebug.so common\/tools\/coverage-threshold.php .phpunit.coverage.php 12.49\"     ],     ...<\/code><\/pre>\n<p>\u0413\u0434\u0435 \u043c\u0430\u0433\u0438\u0447\u0435\u0441\u043a\u0430\u044f \u0446\u0438\u0444\u0440\u0430 12.49 \u2014 \u044d\u0442\u043e \u0442\u0435\u043a\u0443\u0449\u0430\u044f \u043e\u0442\u043f\u0440\u0430\u0432\u043d\u0430\u044f \u0442\u043e\u0447\u043a\u0430 \u2014 \u043f\u0440\u043e\u0446\u0435\u043d\u0442 code coverage, \u043d\u0438\u0436\u0435 \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u043e\u043f\u0443\u0441\u043a\u0430\u0442\u044c\u0441\u044f \u043d\u0435\u043b\u044c\u0437\u044f. \u041e\u043d\u0430 \u043d\u0435 \u0434\u043e\u043b\u0436\u043d\u0430 \u0441\u0438\u043b\u044c\u043d\u043e \u043e\u0442\u0441\u0442\u0430\u0432\u0430\u0442\u044c \u043e\u0442 \u0442\u0435\u043a\u0443\u0449\u0435\u0433\u043e \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f, \u0438 \u043f\u0435\u0440\u0438\u043e\u0434\u0438\u0447\u0435\u0441\u043a\u0438 \u043f\u0440\u0438 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0438 \u043d\u043e\u0432\u044b\u0445 \u0442\u0435\u0441\u0442\u043e\u0432 \u043d\u0443\u0436\u043d\u043e \u043d\u0435 \u0437\u0430\u0431\u044b\u0432\u0430\u0442\u044c \u0435\u0435 \u043f\u043e\u0434\u043a\u0440\u0443\u0447\u0438\u0432\u0430\u0442\u044c.<\/p>\n<h2>\u041f\u043e\u0432\u044b\u0448\u0435\u043d\u0438\u0435 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0430 \u043a\u043e\u0434\u0430 \u0442\u0435\u0441\u0442\u043e\u0432<\/h2>\n<p>\u041a\u043e\u0433\u0434\u0430 \u0442\u0435\u0441\u0442\u043e\u0432 \u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u0441\u044f \u0441\u043e\u0442\u043d\u0438 \u0438\u043b\u0438 \u0442\u044b\u0441\u044f\u0447\u0438, \u0442\u043e \u0432\u043e\u0437\u043d\u0438\u043a\u0430\u0435\u0442 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0430 \u0438\u0445 \u0432\u0437\u0430\u0438\u043c\u043e\u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438. \u041d\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u043a\u043e\u0434 \u0441\u0430\u043c\u0438\u0445 \u0442\u0435\u0441\u0442\u043e\u0432, \u043d\u043e \u0438 \u043a\u043e\u0434 \u043f\u0440\u043e\u0434\u0443\u043a\u0442\u0430 \u0431\u0443\u0434\u0435\u0442 \u043f\u0440\u0435\u043f\u043e\u0434\u043d\u043e\u0441\u0438\u0442\u044c \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u044b\u0435 \u0441\u044e\u0440\u043f\u0440\u0438\u0437\u044b. \u041f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e \u0437\u0430\u043f\u0443\u0441\u043a \u0442\u0435\u0441\u0442\u043e\u0432 \u0438\u0434\u0435\u0442 \u0432 \u0440\u0430\u043c\u043a\u0430\u0445 \u043e\u0434\u043d\u043e\u0433\u043e PHP-\u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0430. \u041b\u044e\u0431\u043e\u0435 \u043a\u044d\u0448\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435, static\u2019\u0438, \u0441\u0438\u043d\u0433\u043b\u0442\u043e\u043d\u044b, \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u044b \u0438\u043b\u0438, \u043d\u0435 \u0434\u0430\u0439 \u0431\u043e\u0433, \u0433\u043b\u043e\u0431\u0430\u043b\u044c\u043d\u044b\u0435 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0435 \u0438 \u0434\u0430\u0436\u0435 \u0437\u0430\u0433\u043b\u0443\u0448\u043a\u0438 \u0438 \u043c\u043e\u043a\u0438 \u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u043e \u0441\u0442\u0430\u043d\u0443\u0442 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u043e\u0439. \u041d\u0443\u0436\u043d\u043e \u043f\u043e\u043d\u0438\u043c\u0430\u0442\u044c, \u0447\u0442\u043e \u0432 \u0431\u043e\u043b\u044c\u0448\u0438\u043d\u0441\u0442\u0432\u0435 \u0441\u043b\u0443\u0447\u0430\u0435\u0432 \u0441\u0432\u044f\u0437\u043d\u043e\u0441\u0442\u044c \u0432\u043e\u0437\u043d\u0438\u043a\u0430\u0435\u0442 \u0441\u043e\u0432\u0435\u0440\u0448\u0435\u043d\u043d\u043e \u043d\u0435\u043e\u0441\u043e\u0437\u043d\u0430\u043d\u043d\u043e, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u043d\u0443\u0436\u043d\u043e \u043f\u0440\u0435\u0432\u0435\u043d\u0442\u0438\u0432\u043d\u043e \u0431\u043e\u0440\u043e\u0442\u044c\u0441\u044f \u0441 \u0447\u0435\u043b\u043e\u0432\u0435\u0447\u0435\u0441\u043a\u0438\u043c \u0444\u0430\u043a\u0442\u043e\u0440\u043e\u043c.<\/p>\n<p>\u041e\u0434\u0438\u043d \u0438\u0437 \u0441\u0442\u0440\u0435\u0441\u0441-\u043c\u0435\u0442\u043e\u0434\u043e\u0432 \u0434\u043b\u044f \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0437\u0430\u043f\u0443\u0441\u043a \u0442\u0435\u0441\u0442\u043e\u0432 \u043a\u043e\u043c\u0430\u043d\u0434\u043e\u0439 <code>composer test -- --process-isolation<\/code>. \u0412 \u0442\u0430\u043a\u043e\u043c \u0440\u0435\u0436\u0438\u043c\u0435 \u043a\u0430\u0436\u0434\u044b\u0439 \u0442\u0435\u0441\u0442 \u0431\u0443\u0434\u0435\u0442 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0442\u044c\u0441\u044f \u0432 \u0440\u0430\u043c\u043a\u0430\u0445 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e\u0433\u043e PHP-\u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0430. \u0418\u0437\u043e\u043b\u044f\u0446\u0438\u044f \u2014 \u044d\u0442\u043e \u043f\u0440\u0435\u043a\u0440\u0430\u0441\u043d\u043e, \u043d\u043e \u043d\u0430 \u043f\u0440\u0430\u043a\u0442\u0438\u043a\u0435 \u0432 \u0442\u0430\u043a\u043e\u043c \u0440\u0435\u0436\u0438\u043c\u0435 \u0432\u043e\u0437\u043d\u0438\u043a\u0430\u0435\u0442 \u0441\u0440\u0430\u0437\u0443 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043d\u044e\u0430\u043d\u0441\u043e\u0432. \u0412\u043e-\u043f\u0435\u0440\u0432\u044b\u0445, \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u044d\u0442\u043e \u0432\u0441\u0435 \u043a\u0440\u0430\u0439\u043d\u0435 \u043c\u0435\u0434\u043b\u0435\u043d\u043d\u043e. \u0412\u043c\u0435\u0441\u0442\u043e 10 \u0441\u0435\u043a\u0443\u043d\u0434 \u0431\u0443\u0434\u0435\u0442 \u0443\u0436\u0435 \u043f\u043e\u0440\u044f\u0434\u043a\u0430 14 \u043c\u0438\u043d\u0443\u0442 \u0432 \u043c\u043e\u0435\u0439 \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u043e\u0439 \u0441\u0438\u0442\u0443\u0430\u0446\u0438\u0438. \u0412\u043e-\u0432\u0442\u043e\u0440\u044b\u0445, \u043d\u0435 \u0432\u0441\u0435 \u0432\u0435\u0449\u0438 \u0431\u0443\u0434\u0443\u0442 \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0432 \u0442\u0430\u043a\u043e\u0439 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0432 data provider\u2019\u0430\u0445 \u043c\u043e\u0436\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u0441\u0435\u0440\u0438\u0430\u043b\u0438\u0437\u0443\u0435\u043c\u044b\u0435 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u044b (\u0430 \u043a\u043e\u043b\u043b\u0435\u0433\u0438-\u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0441\u0442\u044b \u043c\u043e\u0433\u043b\u0438 \u043d\u0430\u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0442\u044c \u0442\u0443\u0434\u0430 \u0443\u0436\u0435 \u0437\u0430\u043c\u044b\u043a\u0430\u043d\u0438\u0439, \u043c\u043e\u043a\u043e\u0432 \u0438 \u0434\u0440\u0443\u0433\u0438\u0445 \u0434\u0438\u043d\u0430\u043c\u0438\u0447\u0435\u0441\u043a\u0438\u0445 \u0440\u0430\u0434\u043e\u0441\u0442\u0435\u0439). \u0421 \u043f\u0435\u0440\u0432\u043e\u0439 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u043e\u0439 \u043c\u043e\u0436\u043d\u043e \u043f\u044b\u0442\u0430\u0442\u044c\u0441\u044f \u0431\u043e\u0440\u043e\u0442\u044c\u0441\u044f \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e <a href=\"https:\/\/github.com\/paratestphp\/paratest\">ParaTest<\/a>, \u043e\u0434\u043d\u0430\u043a\u043e \u0443 \u043d\u0435\u0433\u043e \u0435\u0441\u0442\u044c \u0435\u0449\u0435 \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u044f. <\/p>\n<p>\u041e\u0442\u043d\u043e\u0441\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0439 \u0430\u043b\u044c\u0442\u0435\u0440\u043d\u0430\u0442\u0438\u0432\u043e\u0439 \u043e\u043f\u0446\u0438\u0438 <code>--process-isolation<\/code> \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0437\u0430\u043f\u0443\u0441\u043a \u0442\u0435\u0441\u0442\u043e\u0432 \u0432 \u0441\u043b\u0443\u0447\u0430\u0439\u043d\u043e\u043c \u043f\u043e\u0440\u044f\u0434\u043a\u0435. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u043c\u043e\u0436\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043e\u043f\u0446\u0438\u044e \u043a\u043e\u043c\u0430\u043d\u0434\u043d\u043e\u0439 \u0441\u0442\u0440\u043e\u043a\u0438 <code>--order-by=random<\/code>, \u043b\u0438\u0431\u043e \u0443\u043a\u0430\u0437\u0430\u0442\u044c \u0432 phpunit.xml.dist \u0434\u043b\u044f \u043a\u043e\u0440\u043d\u0435\u0432\u043e\u0433\u043e \u0442\u0435\u0433\u0430 \u0430\u0442\u0440\u0438\u0431\u0443\u0442 <code>executionOrder=\"random\"<\/code>. \u041b\u043e\u043a\u0430\u043b\u0438\u0437\u043e\u0432\u044b\u0432\u0430\u0442\u044c \u0438 \u043e\u0442\u043b\u0430\u0436\u0438\u0432\u0430\u0442\u044c \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u044b \u0437\u0430\u043c\u0435\u0442\u043d\u043e \u0441\u043b\u043e\u0436\u043d\u0435\u0435, \u0447\u0435\u043c \u0432 \u0441\u043b\u0443\u0447\u0430\u0435 \u0441 <code>--process-isolation<\/code>, \u043d\u043e \u0432\u043f\u043e\u043b\u043d\u0435 \u0440\u0435\u0430\u043b\u044c\u043d\u043e. \u041e\u0431\u0440\u0430\u0449\u0430\u0435\u043c \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435 \u043d\u0430 \u0441\u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0439 random seed \u0432 \u043d\u0430\u0447\u0430\u043b\u0435 \u0432\u044b\u0432\u043e\u0434\u0430 \u043e\u0442 PHPUnit \u0438 \u043f\u043e\u0432\u0442\u043e\u0440\u044f\u0435\u043c \u043f\u0440\u043e\u0433\u043e\u043d \u043a\u043e\u043c\u0430\u043d\u0434\u043e\u0439 \u043d\u0438\u0436\u0435:<\/p>\n<pre><code>composer test -- --order-by=random --random-order-seed=1617073223<\/code><\/pre>\n<p>\u0422\u0435\u0441\u0442, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u0430\u0434\u0430\u0435\u0442, \u043c\u043e\u0436\u0435\u0442 \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u044c\u0441\u044f \u0437\u0430 \u0441\u043e\u0442\u043d\u0438 \u0442\u0435\u0441\u0442\u043e\u0432 \u043e\u0442 \u0442\u043e\u0433\u043e, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0441\u043e\u0437\u0434\u0430\u0435\u0442 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u044b. \u0414\u043b\u044f \u0442\u043e\u0433\u043e, \u0447\u0442\u043e\u0431\u044b \u043f\u043e \u0441\u0443\u0442\u0438 \u043f\u0440\u043e\u0441\u0438\u043c\u0443\u043b\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043f\u043e\u0432\u0435\u0434\u0435\u043d\u0438\u0435 \u043e\u043f\u0446\u0438\u0438 <code>--process-isolation<\/code>, \u043c\u043e\u0436\u043d\u043e \u0432 \u0440\u0430\u043c\u043a\u0430\u0445 setUp\/tearDown \u0441\u0431\u0440\u0430\u0441\u044b\u0432\u0430\u0442\u044c \u043f\u0440\u0438\u043d\u0443\u0434\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0432\u0441\u0435 \u043a\u044d\u0448\u0438, \u043f\u0440\u0438\u0432\u043e\u0434\u0438\u0442\u044c \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044e \u043c\u043e\u043a\u043e\u0432 \u0432 \u0438\u0441\u0445\u043e\u0434\u043d\u043e\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u0438 \u0434\u0435\u043b\u0430\u0442\u044c \u043f\u0440\u043e\u0447\u0438\u0435 \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u043e\u043d\u043d\u044b\u0435 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f. \u0412 \u0438\u0442\u043e\u0433\u0435 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u0432\u0437\u0430\u0438\u043c\u043e\u0437\u0430\u0432\u0438\u0441\u0438\u043c\u044b\u0445 \u0442\u0435\u0441\u0442\u043e\u0432 \u0441\u0438\u043b\u044c\u043d\u043e \u043e\u0441\u043b\u043e\u0436\u043d\u044f\u0435\u0442\u0441\u044f. \u0412\u043e\u0437\u043c\u043e\u0436\u043d\u043e, \u0442\u0430\u043a\u043e\u0439 \u0442\u0435\u0441\u0442 \u043d\u0435 \u0431\u0443\u0434\u0435\u0442 \u043f\u043e\u0439\u043c\u0430\u043d \u0441 \u043f\u0435\u0440\u0432\u043e\u0439 \u043f\u043e\u043f\u044b\u0442\u043a\u0438, \u043d\u043e \u043f\u043e\u0441\u043b\u0435 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043f\u0440\u043e\u0433\u043e\u043d\u043e\u0432 \u043e\u043d \u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u043e \u0432\u0441\u043f\u043b\u044b\u0432\u0435\u0442. <\/p>\n<p>\u0415\u0449\u0435 \u043e\u0434\u0438\u043d \u043c\u043e\u043c\u0435\u043d\u0442, \u043d\u0430 \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0441\u0442\u043e\u0438\u0442 \u043e\u0431\u0440\u0430\u0442\u0438\u0442\u044c \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435, \u044d\u0442\u043e \u0441\u043a\u043e\u0440\u043e\u0441\u0442\u044c \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e\u0433\u043e \u0442\u0435\u0441\u0442\u0430. \u041e\u0434\u0438\u043d \u0438\u0437 \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u043e\u0432 \u0435\u0435 \u0443\u0437\u043d\u0430\u0442\u044c \u2014 \u044d\u0442\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 \u043e\u043f\u0446\u0438\u0438 <code>--log-junit<\/code>. \u0412 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0435 \u0431\u0443\u0434\u0435\u0442 \u043f\u043e\u043b\u0443\u0447\u0435\u043d XML-\u0444\u0430\u0439\u043b \u0441 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0435\u0439 \u043e \u0432\u0440\u0435\u043c\u0435\u043d\u0438, \u0437\u0430\u0442\u0440\u0430\u0447\u0435\u043d\u043d\u043e\u043c \u043d\u0430 \u043a\u0430\u0436\u0434\u044b\u0439 \u0442\u0435\u0441\u0442. \u041c\u043e\u0436\u043d\u043e \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u043f\u0440\u043e\u0441\u0442\u0435\u043d\u044c\u043a\u0438\u0439 \u0441\u043a\u0440\u0438\u043f\u0442 \u0434\u043b\u044f \u0430\u043d\u0430\u043b\u0438\u0437\u0430, \u0430 \u043c\u043e\u0436\u043d\u043e \u0432\u043e\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u0432\u0441\u0442\u0440\u043e\u0435\u043d\u043d\u044b\u043c \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u043e\u043c \u0432 PhpStorm \u0438 \u0441\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u043a\u043e\u0439 \u043f\u043e \u0432\u0440\u0435\u043c\u0435\u043d\u0438:<\/p>\n<figure class=\"\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/ed0\/8d0\/35f\/ed08d035f9f3a22c02efa55cbf514268.png\" width=\"492\" height=\"269\"><figcaption><\/figcaption><\/figure>\n<p>\u041a\u043e\u0434 \u0442\u0435\u0441\u0442\u043e\u0432 \u2014 \u044d\u0442\u043e \u0442\u043e\u0436\u0435 \u043a\u043e\u0434, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u043d\u0435 \u0441\u0442\u043e\u0438\u0442 \u0438\u0433\u043d\u043e\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u043d\u0430 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0438\u0435 \u043f\u0440\u0438\u043d\u044f\u0442\u043e\u0433\u043e \u0441\u0442\u0438\u043b\u044f \u0438\u043b\u0438 \u0441\u043b\u0435\u0434\u043e\u0432\u0430\u043d\u0438\u044f \u043e\u0431\u0449\u0435\u043f\u0440\u0438\u043d\u044f\u0442\u044b\u043c \u043f\u0440\u0430\u043a\u0442\u0438\u043a\u0430\u043c \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u044f \u0445\u043e\u0440\u043e\u0448\u0435\u0433\u043e \u043a\u043e\u0434\u0430. \u0410\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0435 \u043b\u0438\u043d\u0442\u0435\u0440\u044b \u0442\u0430\u043a\u0436\u0435 \u0434\u043e\u043b\u0436\u043d\u044b \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0442\u044c \u0438 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u044e \u0441 \u0442\u0435\u0441\u0442\u0430\u043c\u0438. \u041d\u0430 \u0441\u0430\u043c\u043e\u043c \u0434\u0435\u043b\u0435, \u0442\u0435\u0441\u0442\u044b \u0441 \u043d\u0438\u0437\u043a\u0438\u043c \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u043e\u043c \u043a\u043e\u0434\u0430 \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u0447\u0430\u0441\u0442\u043e \u0432 \u0438\u0442\u043e\u0433\u0435 \u043e\u043a\u0430\u0437\u044b\u0432\u0430\u044e\u0442\u0441\u044f \u201c\u043c\u043e\u0440\u0433\u0430\u044e\u0449\u0438\u043c\u0438\u201d (flaky) \u0442\u0435\u0441\u0442\u0430\u043c\u0438.<\/p>\n<h2>\u041f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0430 \u0434\u0432\u0443\u0445 \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c (Linux \u0438 Windows)<\/h2>\n<p>\u0415\u0441\u043b\u0438 \u0432\u0430\u043c \u201c\u043f\u043e\u0441\u0447\u0430\u0441\u0442\u043b\u0438\u0432\u0438\u043b\u043e\u0441\u044c\u201d \u043f\u0438\u0441\u0430\u0442\u044c \u043f\u0440\u043e\u0434\u0443\u043a\u0442 \u043f\u043e\u0434 \u0434\u0432\u0435 \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u044b (Linux \u0438 Windows), \u0442\u043e \u0432 \u0440\u0430\u043c\u043a\u0430\u0445 \u0442\u0435\u0441\u0442\u043e\u0432 \u043d\u0443\u0436\u043d\u043e \u0443\u0447\u0438\u0442\u044b\u0432\u0430\u0442\u044c \u0442\u043e, \u043a\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442\u0441\u044f \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u043e\u0437\u0430\u0432\u0438\u0441\u0438\u043c\u044b\u0439 \u043a\u043e\u0434. \u201c\u0412\u0438\u043b\u043a\u0438\u201d \u043f\u043e \u043a\u043e\u043d\u0441\u0442\u0430\u043d\u0442\u0435 PHP_OS, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 PHP_EOL \u2014 \u0432\u0441\u0435 \u044d\u0442\u043e \u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u043e \u0441\u043e\u0437\u0434\u0430\u0441\u0442 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u044b, \u0430 \u043f\u0435\u0440\u0435\u0431\u0438\u0442\u044c \u0438\u0445 \u043d\u0435 \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u0441\u044f \u0434\u0430\u0436\u0435 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e runkit\u2019\u0430. \u0412 \u0438\u0434\u0435\u0430\u043b\u0435, \u043f\u0440\u043e\u0433\u043e\u043d \u0442\u0435\u0441\u0442\u043e\u0432 \u043d\u0430 PHP \u043a\u043e\u0434 \u0434\u043b\u044f Windows \u0434\u043e\u043b\u0436\u0435\u043d \u0438\u043c\u0435\u0442\u044c \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0438 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a, \u0443 \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u0440\u0430\u0431\u043e\u0447\u0430\u044f \u043c\u0430\u0448\u0438\u043d\u0430 \u043f\u043e\u0434 Linux \u0438\u043b\u0438 Mac. \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u044f \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u044b \u043b\u0443\u0447\u0448\u0435 \u0441\u0440\u0430\u0437\u0443 \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0438\u0440\u0443\u0435\u043c\u044b\u043c. \u041d\u0430 \u043f\u043e\u0437\u0434\u043d\u0438\u0445 \u044d\u0442\u0430\u043f\u0430\u0445 \u0432\u043a\u0440\u0443\u0447\u0438\u0432\u0430\u0442\u044c \u0435\u0433\u043e \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u0442\u044f\u0436\u0435\u043b\u043e. \u0415\u0441\u043b\u0438 \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u043e\u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0433\u043e \u043a\u043e\u0434\u0430 \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u043c\u043d\u043e\u0433\u043e, \u043c\u043e\u0436\u0435\u0442 \u043e\u043a\u0430\u0437\u0430\u0442\u044c\u0441\u044f \u043f\u0440\u043e\u0449\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0434\u0432\u0430 \u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u0442\u0435\u0441\u0442\u043e\u0432, \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u044f \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u0443 \u0447\u0435\u0440\u0435\u0437 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u0443\u044e \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u044f:<\/p>\n<pre><code>PHP_OS=WINNT composer test PHP_OS=Linux composer test<\/code><\/pre>\n<h2>\u041f\u043e\u043b\u0435 \u0434\u043b\u044f \u044d\u043a\u0441\u043f\u0435\u0440\u0438\u043c\u0435\u043d\u0442\u043e\u0432<\/h2>\n<p>\u041f\u0435\u0440\u0438\u043e\u0434\u0438\u0447\u0435\u0441\u043a\u0438 \u0432\u044b\u0445\u043e\u0434\u044f\u0442 \u043d\u043e\u0432\u044b\u0435 \u201c\u043c\u0430\u0436\u043e\u0440\u043d\u044b\u0435\u201d \u0432\u0435\u0440\u0441\u0438\u0438 PHP, \u0438 \u0441\u0430\u043c\u044b\u0439 \u043f\u0435\u0440\u0432\u044b\u0439 \u0448\u0430\u0433 \u0438 \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u0431\u044b\u0441\u0442\u0440\u044b\u0439 \u0441\u043f\u043e\u0441\u043e\u0431 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u0438 \u043f\u043e\u0438\u0441\u043a\u0430 \u043f\u0440\u043e\u0431\u043b\u0435\u043c \u2014 \u044d\u0442\u043e \u043f\u0440\u043e\u0433\u043e\u043d \u0442\u0435\u0441\u0442\u043e\u0432. \u0412 \u044d\u0442\u043e\u043c \u0441\u0438\u043b\u044c\u043d\u043e \u043f\u043e\u043c\u043e\u0433\u0430\u0435\u0442 Docker \u0438 \u0443\u043f\u043e\u043c\u044f\u043d\u0443\u0442\u044b\u0439 \u0432\u044b\u0448\u0435 Dockerfile, \u0447\u0442\u043e\u0431\u044b \u043d\u0435 \u0432\u043b\u0438\u044f\u0442\u044c \u043d\u0430 \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u0443\u044e \u043c\u0430\u0448\u0438\u043d\u0443. \u0412\u0435\u0434\u044c \u0434\u043b\u044f \u0431\u043e\u043b\u044c\u0448\u043e\u0433\u043e \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u043c\u043e\u043c\u0435\u043d\u0442 \u0433\u043e\u0442\u043e\u0432\u043d\u043e\u0441\u0442\u0438 \u043a\u043e\u0434\u043e\u0432\u043e\u0439 \u0431\u0430\u0437\u044b \u043a \u043d\u043e\u0432\u043e\u0439 \u0432\u0435\u0440\u0441\u0438\u0438 PHP \u0438 \u0441\u0430\u043c \u043c\u043e\u043c\u0435\u043d\u0442 \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u0430 \u043d\u0430 \u043d\u043e\u0432\u0443\u044e \u0432\u0435\u0440\u0441\u0438\u044e \u2014 \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u0440\u0430\u0437\u043d\u0435\u0441\u0435\u043d\u043d\u044b\u0435 \u043f\u043e \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u0441\u043e\u0431\u044b\u0442\u0438\u044f. \u0421\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0435\u043d\u043d\u043e, \u0432 \u043f\u0435\u0440\u0432\u0443\u044e \u043e\u0447\u0435\u0440\u0435\u0434\u044c \u0434\u0435\u043b\u0430\u044e\u0442\u0441\u044f \u201cforward compatible\u201d \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f, \u0438 \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442\u0441\u044f \u0440\u0430\u0431\u043e\u0442\u043e\u0441\u043f\u043e\u0441\u043e\u0431\u043d\u043e\u0441\u0442\u044c \u0442\u0435\u0441\u0442\u043e\u0432 \u043d\u0430 \u0434\u0432\u0443\u0445 \u0432\u0435\u0440\u0441\u0438\u044f\u0445 (\u0441\u0442\u0430\u0440\u043e\u0439 \u0438 \u043d\u043e\u0432\u043e\u0439 \u0432\u0435\u0440\u0441\u0438\u0438 PHP).<\/p>\n<p>\u041f\u0440\u043e\u0432\u0435\u0440\u043a\u0443 \u043d\u043e\u0432\u044b\u0445 \u0444\u0438\u0447\u0435\u0439 \u044f\u0437\u044b\u043a\u0430 \u0438 \u0441\u0438\u043d\u0442\u0430\u043a\u0441\u0438\u0441\u0430 \u0442\u0430\u043a\u0436\u0435 \u043e\u0447\u0435\u043d\u044c \u0443\u0434\u043e\u0431\u043d\u043e \u0434\u0435\u043b\u0430\u0442\u044c \u0432 \u0440\u0430\u043c\u043a\u0430\u0445 \u043a\u043e\u0434\u0430 \u0442\u0435\u0441\u0442\u043e\u0432. \u042d\u0442\u043e \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e, \u0442\u0430\u043a \u043a\u0430\u043a \u043a\u043e\u0434 \u0442\u0435\u0441\u0442\u043e\u0432 \u043d\u0435 \u0438\u0434\u0435\u0442 \u0432 \u0440\u0435\u043b\u0438\u0437, \u0438 \u043f\u0440\u0438 \u044d\u0442\u043e\u043c \u0432\u044b \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442\u0435 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u201c\u043f\u0440\u043e\u0447\u0443\u0432\u0441\u0442\u0432\u043e\u0432\u0430\u0442\u044c\u201d \u043d\u043e\u0432\u043e\u0432\u0432\u0435\u0434\u0435\u043d\u0438\u044f. \u041d\u0430 \u0441\u0430\u043c\u043e\u043c \u0434\u0435\u043b\u0435, \u044d\u0442\u043e \u043c\u043e\u0433\u0443\u0442 \u0431\u044b\u0442\u044c \u043b\u044e\u0431\u044b\u0435 \u043d\u043e\u0432\u043e\u0432\u0432\u0435\u0434\u0435\u043d\u0438\u044f \u0432 \u0440\u0430\u043c\u043a\u0430\u0445 \u043a\u043e\u0434\u043e\u0432\u043e\u0439 \u0431\u0430\u0437\u044b (\u043d\u0435\u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u043e \u043d\u043e\u0432\u044b\u0435 \u0444\u0438\u0447\u0438 \u044f\u0437\u044b\u043a\u0430). \u0414\u043e\u043f\u0443\u0441\u0442\u0438\u043c, \u0440\u0435\u0448\u0438\u043b\u0438, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u044c PSR-2 \u0438 \u0443\u0431\u0440\u0430\u0442\u044c \u0441\u0438\u043c\u0432\u043e\u043b \u043d\u0438\u0436\u043d\u0435\u0433\u043e \u043f\u043e\u0434\u0447\u0435\u0440\u043a\u0438\u0432\u0430\u043d\u0438\u044f \u0438\u0437 \u0438\u043c\u0435\u043d protected \u0438 private \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0445 \u0438 \u043c\u0435\u0442\u043e\u0434\u043e\u0432. \u041f\u0435\u0440\u0432\u043e\u0435, \u0433\u0434\u0435 \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u043f\u0440\u043e\u0431\u043e\u0432\u0430\u0442\u044c \u043e\u0431\u043a\u0430\u0442\u0430\u0442\u044c \u0441\u043a\u0440\u0438\u043f\u0442\u044b \u0437\u0430\u043c\u0435\u043d\u044b \u0438 \u0440\u0435\u0444\u0430\u043a\u0442\u043e\u0440\u0438\u043d\u0433\u0430, \u044d\u0442\u043e \u043a\u043e\u0434 \u0442\u0435\u0441\u0442\u043e\u0432.<\/p>\n<h2>\u0417\u0430\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435<\/h2>\n<p>\u0412 \u0437\u0430\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 \u043e\u0442\u043c\u0435\u0447\u0443 \u043e\u0441\u043d\u043e\u0432\u043d\u044b\u0435 \u043c\u043e\u043c\u0435\u043d\u0442\u044b. \u041a\u043e\u0433\u0434\u0430 \u0442\u0435\u0441\u0442\u043e\u0432 \u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u0441\u044f \u043c\u043d\u043e\u0433\u043e, \u0442\u043e \u0438\u0445 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u043e \u0432\u044b\u0445\u043e\u0434\u0438\u0442 \u043d\u0430 \u043f\u0435\u0440\u0432\u044b\u0439 \u043f\u043b\u0430\u043d. \u041a\u043e\u043d\u0442\u0440\u043e\u043b\u044c \u0443\u0440\u043e\u0432\u043d\u044f \u043f\u043e\u043a\u0440\u044b\u0442\u0438\u044f \u043b\u0443\u0447\u0448\u0435 \u043e\u0442\u0434\u0430\u0442\u044c \u043d\u0430 \u043e\u0442\u043a\u0443\u043f \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u043c \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0430\u043c pull request\u2019\u043e\u0432, \u0430 \u043a\u043e\u0434 \u0442\u0435\u0441\u0442\u043e\u0432 \u2014 \u044d\u0442\u043e \u043e\u0447\u0435\u043d\u044c \u0443\u0434\u043e\u0431\u043d\u043e\u0435 \u0438 \u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e\u0435 \u043f\u043e\u043b\u0435 \u0434\u043b\u044f \u044d\u043a\u0441\u043f\u0435\u0440\u0438\u043c\u0435\u043d\u0442\u043e\u0432.<\/p>\n<p>\u041a\u0430\u043a \u0433\u043e\u0432\u043e\u0440\u0438\u0442\u0441\u044f, \u0434\u0430 \u043f\u0440\u0438\u0431\u0443\u0434\u0443\u0442 \u0441 \u0432\u0430\u043c\u0438 \u0432\u0441\u0435\u0433\u0434\u0430 \u201c\u0437\u0435\u043b\u0435\u043d\u044b\u0435\u201d \u0442\u0435\u0441\u0442\u044b \ud83d\ude42<\/p>\n<figure class=\"\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/097\/36c\/5c0\/09736c5c071b91f1923a43b988cd256c.png\" width=\"500\" height=\"357\"><figcaption><\/figcaption><\/figure>\n<\/div>\n<p> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/company\/plesk\/blog\/552998\/\"> https:\/\/habr.com\/ru\/company\/plesk\/blog\/552998\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"\n<div class=\"post__text post__text_v2\" id=\"post-content-body\">\n<figure class=\"float full-width\"><figcaption><\/figcaption><\/figure>\n<p>\u041d\u0435 \u0441\u0435\u043a\u0440\u0435\u0442, \u0447\u0442\u043e \u0447\u0435\u043c \u0431\u043e\u043b\u044c\u0448\u0435 \u043f\u0440\u043e\u0435\u043a\u0442, \u0442\u0435\u043c \u0441 \u0431\u043e\u043b\u044c\u0448\u0438\u043c \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e\u043c \u043f\u0440\u043e\u0431\u043b\u0435\u043c \u043e\u043d \u0441\u0442\u0430\u043b\u043a\u0438\u0432\u0430\u0435\u0442\u0441\u044f \u0434\u0430\u0436\u0435 \u0432 \u0441\u0430\u043c\u044b\u0445 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0430\u0440\u043d\u044b\u0445 \u0430\u0441\u043f\u0435\u043a\u0442\u0430\u0445. \u0412 \u043f\u0440\u043e\u0434\u0443\u043a\u0442\u0435 <a href=\"https:\/\/www.plesk.com\/\">Plesk<\/a>, \u043d\u0430\u0434 \u043a\u043e\u0442\u043e\u0440\u044b\u043c \u044f \u0440\u0430\u0431\u043e\u0442\u0430\u044e, PHP \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043e\u0434\u043d\u0438\u043c \u0438\u0437 \u043e\u0441\u043d\u043e\u0432\u043d\u044b\u0445 \u044f\u0437\u044b\u043a\u043e\u0432, \u0438 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u043a\u043e\u0434\u0430 \u043d\u0430 \u043d\u0435\u043c \u043f\u0440\u0435\u0432\u044b\u0448\u0430\u0435\u0442 1 \u043c\u0438\u043b\u043b\u0438\u043e\u043d \u0441\u0442\u0440\u043e\u043a. \u0421\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0435\u043d\u043d\u043e, \u043c\u044b \u0430\u043a\u0442\u0438\u0432\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c <a href=\"https:\/\/phpunit.de\/\">PHPUnit<\/a> \u0434\u043b\u044f \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f. \u041a\u0440\u043e\u043c\u0435 \u0431\u043e\u043b\u044c\u0448\u043e\u0433\u043e \u043e\u0431\u044a\u0435\u043c\u0430 \u043a\u043e\u0434\u0430, \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0430 \u0434\u0432\u0443\u0445 \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c (Linux \u0438 Windows) \u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u043d\u044e\u0430\u043d\u0441\u044b, \u043a\u0430\u043a \u0438 \u0442\u043e\u0442 \u0444\u0430\u043a\u0442, \u0447\u0442\u043e \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442\u0441\u044f \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0431\u0440\u0430\u043d\u0447\u0435\u0439 \u0441 \u043f\u0440\u0438\u043b\u0438\u0447\u043d\u043e\u0439 \u0440\u0430\u0437\u043d\u0438\u0446\u0435\u0439 \u0432\u043e\u0437\u0440\u0430\u0441\u0442\u0430 (\u043a\u0440\u0443\u043f\u043d\u044b\u0435 \u0440\u0435\u043b\u0438\u0437\u044b), \u0430 \u0430\u043a\u0442\u0438\u0432\u043d\u043e \u0432\u043d\u043e\u0441\u044f\u0442 \u043f\u0440\u0430\u0432\u043a\u0438 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0434\u0435\u0441\u044f\u0442\u043a\u043e\u0432 \u0438\u043d\u0436\u0435\u043d\u0435\u0440\u043e\u0432. \u0412 \u0441\u0442\u0430\u0442\u044c\u0435 \u044f \u0445\u043e\u0447\u0443 \u043f\u043e\u0434\u0435\u043b\u0438\u0442\u044c\u0441\u044f \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u043c\u0438 \u043f\u0440\u0430\u043a\u0442\u0438\u043a\u0430\u043c\u0438, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043c\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c \u043f\u0440\u0438 \u0440\u0430\u0431\u043e\u0442\u0435 \u0441 PHPUnit. <\/p>\n<h2>\u0423\u043d\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044f<\/h2>\n<p>\u041f\u0435\u0440\u0432\u044b\u0439 \u043c\u043e\u043c\u0435\u043d\u0442, \u043d\u0430 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u043d\u0443\u0436\u043d\u043e \u043e\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c\u0441\u044f, \u2014 \u044d\u0442\u043e \u0443\u043d\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044f. \u0415\u0441\u043b\u0438 \u0432\u044b \u0435\u0434\u0438\u043d\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0439 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u043f\u0440\u043e\u0435\u043a\u0442\u0430, \u0442\u043e, \u043a\u043e\u043d\u0435\u0447\u043d\u043e, \u0434\u0435\u043b\u0430\u0442\u044c \u043c\u043e\u0436\u043d\u043e \u043a\u0430\u043a \u0443\u0433\u043e\u0434\u043d\u043e. \u041d\u043e \u0435\u0441\u043b\u0438 \u0432\u044b \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442\u0435 \u043d\u0430\u0434 \u043f\u0440\u043e\u0435\u043a\u0442\u043e\u043c \u043d\u0435 \u043e\u0434\u0438\u043d, \u0442\u043e \u043b\u0443\u0447\u0448\u0435 \u0434\u0435\u043b\u0430\u0442\u044c \u0432\u0441\u0435 \u0435\u0434\u0438\u043d\u043e\u043e\u0431\u0440\u0430\u0437\u043d\u043e \u0432 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0438\u0438 \u0441 \u043f\u0440\u0438\u043d\u044f\u0442\u044b\u043c\u0438 \u043f\u0440\u0430\u043a\u0442\u0438\u043a\u0430\u043c\u0438.<\/p>\n<p>\u0412 \u043c\u0438\u0440\u0435 PHP \u043f\u0440\u0438\u043d\u044f\u0442\u043e, \u0447\u0442\u043e\u0431\u044b \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u0443\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u043b\u0438\u0441\u044c \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e <code>composer install<\/code>, \u0430 \u043a\u043e\u043c\u0430\u043d\u0434\u0430 <code>composer test<\/code> \u043f\u0440\u043e\u0433\u043e\u043d\u044f\u043b\u0430 \u043d\u0430\u0431\u043e\u0440 \u0442\u0435\u0441\u0442\u043e\u0432. \u0412 \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u0435 PHPUnit \u044d\u0442\u043e \u043e\u0437\u043d\u0430\u0447\u0430\u0435\u0442 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0435. \u0417\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u044c \u043d\u0430 PHPUnit \u0434\u043e\u043b\u0436\u043d\u0430 \u043f\u0440\u0438\u0441\u0443\u0442\u0441\u0442\u0432\u043e\u0432\u0430\u0442\u044c \u0432 \u0440\u0430\u0437\u0434\u0435\u043b\u0435 &#171;require-dev&#187; \u0432 composer.json:<\/p>\n<pre><code class=\"json\">  \"require-dev\": {     ...     \"phpunit\/phpunit\": \"^9.5\",<\/code><\/pre>\n<p>\u0412 \u0440\u0430\u0437\u0434\u0435\u043b\u0435 scripts, \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0435\u043d\u043d\u043e, \u0434\u043e\u043b\u0436\u043d\u043e \u043f\u0440\u0438\u0441\u0443\u0442\u0441\u0442\u0432\u043e\u0432\u0430\u0442\u044c \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u0435 \u0434\u043b\u044f \u043a\u043e\u043c\u0430\u043d\u0434\u044b test:&nbsp;<\/p>\n<pre><code class=\"json\">  \"scripts\": {     ...     \"test\": \"phpunit\",<\/code><\/pre>\n<p>\u0420\u0430\u0437\u043b\u0438\u0447\u043d\u044b\u0435 \u043b\u0438\u043d\u0442\u0435\u0440\u044b \u0438 \u0441\u0442\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0435 \u0430\u043d\u0430\u043b\u0438\u0437\u0430\u0442\u043e\u0440\u044b, \u0435\u0441\u043b\u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0442\u0441\u044f, \u0442\u043e\u0436\u0435 \u0434\u043e\u043b\u0436\u043d\u044b \u043e\u043a\u0430\u0437\u0430\u0442\u044c\u0441\u044f \u0447\u0430\u0441\u0442\u044c\u044e \u044d\u0442\u043e\u0439 \u043a\u043e\u043c\u0430\u043d\u0434\u044b:<\/p>\n<pre><code class=\"json\">  \"scripts\": {     ...     \"test\": [       \"@phpcs\",       \"@phpstan\",       \"@psalm\",       \"@phpunit\"     ],<\/code><\/pre>\n<p>\u0414\u0430\u043b\u0435\u0435 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044e \u0434\u043b\u044f PHPUnit \u043d\u0443\u0436\u043d\u043e \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u0442\u044c \u0432 phpunit.xml.dist, \u0430 \u0444\u0430\u0439\u043b phpunit.xml \u0437\u0430\u043d\u0435\u0441\u0442\u0438 \u0432 .gitignore. \u0422\u0435\u043c \u0441\u0430\u043c\u044b\u043c \u043c\u044b \u0443\u043d\u0438\u0444\u0438\u0446\u0438\u0440\u0443\u0435\u043c \u043e\u043f\u0446\u0438\u0438 \u0437\u0430\u043f\u0443\u0441\u043a\u0430 PHPUnit, \u043e\u0441\u0442\u0430\u0432\u043b\u044f\u044f \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u043e\u0432\u0435\u0440\u0440\u0430\u0439\u0434\u0430 \u0434\u043b\u044f \u043a\u0430\u043a\u0438\u0445-\u0442\u043e \u044d\u043a\u0441\u043f\u0435\u0440\u0438\u043c\u0435\u043d\u0442\u043e\u0432. \u0420\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0439 \u043f\u043e\u0441\u043b\u0435 \u043a\u043b\u043e\u043d\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f, \u043f\u0440\u043e\u0433\u043e\u043d\u0430 <code>composer install<\/code> \u0438 \u0437\u0430\u043f\u0443\u0441\u043a\u0430 <code>composer test<\/code> \u043d\u0435 \u0434\u043e\u043b\u0436\u0435\u043d \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u0442\u044c \u043a\u0430\u043a\u0438\u0445-\u0442\u043e \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0445 \u043c\u0430\u043d\u0438\u043f\u0443\u043b\u044f\u0446\u0438\u0439. \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u0432 phpunit.xml.dist \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u043c, \u0433\u0434\u0435 \u0438\u0441\u043a\u0430\u0442\u044c \u0442\u0435\u0441\u0442\u044b, \u0447\u0442\u043e \u0438\u0441\u043a\u043b\u044e\u0447\u0430\u0442\u044c, \u043a\u0430\u043a\u0438\u0435 \u043e\u043f\u0446\u0438\u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0438 \u0442.\u043f.<\/p>\n<pre><code class=\"xml\">&lt;?xml version=\"1.0\"?&gt; &lt;phpunit   xmlns:xsi=\"http:\/\/www.w3.org\/2001\/XMLSchema-instance\"   bootstrap=\"common\/php\/tests\/bootstrap.php\"   executionOrder=\"random\"   ... &gt;   &lt;php&gt;     &lt;ini name=\"memory_limit\" value=\"-1\"\/&gt;     &lt;ini name=\"display_errors\" value=\"true\"\/&gt;     ...   &lt;\/php&gt;   &lt;testsuites&gt;     &lt;testsuite name=\"Plesk Common TestSuite\"&gt;       &lt;directory&gt;common\/php\/tests&lt;\/directory&gt;       &lt;exclude&gt;common\/php\/tests\/stubs&lt;\/exclude&gt;       ...     &lt;\/testsuite&gt;   &lt;\/testsuites&gt;   &lt;coverage includeUncoveredFiles=\"true\"&gt;     ...   &lt;\/coverage&gt; &lt;\/phpunit&gt; <\/code><\/pre>\n<p>\u041e\u0441\u0442\u0430\u043b\u043e\u0441\u044c \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u0442\u044c\u0441\u044f \u0441 \u0432\u0435\u0440\u0441\u0438\u0435\u0439 PHP, \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u043c\u0438 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u044f\u043c\u0438 \u0438 \u0437\u0430\u043d\u0435\u0441\u0442\u0438 \u044d\u0442\u0443 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u0432 composer.json:<\/p>\n<pre><code class=\"json\">  \"require\": {     \"php\": \"^7.4\",     \"ext-fileinfo\": \"*\",     \"ext-intl\": \"*\",     \"ext-json\": \"*\",     \"ext-mbstring\": \"*\",     ...   }<\/code><\/pre>\n<p>\u0411\u0430\u0437\u043e\u0432\u0430\u044f \u043f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u043a\u0430 \u0437\u0430\u043a\u043e\u043d\u0447\u0435\u043d\u0430. \u0421 \u043e\u0434\u043d\u043e\u0439 \u0441\u0442\u043e\u0440\u043e\u043d\u044b, \u0432\u0441\u0435 \u043f\u0440\u043e\u0441\u0442\u043e. \u0421 \u0434\u0440\u0443\u0433\u043e\u0439 \u0441\u0442\u043e\u0440\u043e\u043d\u044b, \u0440\u0435\u0433\u0443\u043b\u044f\u0440\u043d\u043e \u043f\u043e\u043f\u0430\u0434\u0430\u044e\u0442\u0441\u044f \u043f\u0440\u043e\u0435\u043a\u0442\u044b, \u0433\u0434\u0435 \u043a\u0430\u043a\u043e\u0439-\u0442\u043e \u0438\u0437 \u043c\u043e\u043c\u0435\u043d\u0442\u043e\u0432 \u0432\u044b\u0448\u0435 \u043e\u043a\u0430\u0437\u0430\u043b\u0441\u044f \u043f\u0440\u043e\u0438\u0433\u043d\u043e\u0440\u0438\u0440\u043e\u0432\u0430\u043d.<\/p>\n<h2>Docker<\/h2>\n<p>\u0410 \u043a\u0443\u0434\u0430 \u0436\u0435 \u0431\u0435\u0437 \u043d\u0435\u0433\u043e? \u0420\u0430\u0437 \u0443\u0436 \u043c\u044b \u0437\u0430\u0433\u043e\u0432\u043e\u0440\u0438\u043b\u0438 \u043e\u0431 \u0443\u043d\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438, \u0442\u043e \u043d\u0435\u043e\u0446\u0435\u043d\u0438\u043c\u0443\u044e \u043f\u043e\u043c\u043e\u0449\u044c \u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442 \u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 <a href=\"https:\/\/docs.docker.com\/language\/nodejs\/run-tests\/\">Docker\u2019\u0430<\/a>. \u0420\u0435\u0447\u044c \u043d\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u043e \u0435\u0433\u043e \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u0438 \u0434\u043b\u044f \u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u0442\u0435\u0441\u0442\u043e\u0432 \u0432 \u0440\u0430\u043c\u043a\u0430\u0445 CI-\u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0430. \u0414\u043b\u044f \u0442\u0435\u0445, \u043a\u0442\u043e \u043d\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442 PHP \u0432 \u0435\u0436\u0435\u0434\u043d\u0435\u0432\u043d\u043e\u0439 \u0440\u0430\u0431\u043e\u0442\u0435, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0434\u043b\u044f QA-\u0438\u043d\u0436\u0435\u043d\u0435\u0440\u0430, \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u0443\u0434\u043e\u0431\u043d\u044b\u043c \u0437\u0430\u043f\u0443\u0441\u043a \u0442\u0435\u0441\u0442\u043e\u0432 \u0432 Docker. \u0423\u0434\u043e\u0431\u043d\u044b\u043c \u0432 \u043f\u0435\u0440\u0432\u0443\u044e \u043e\u0447\u0435\u0440\u0435\u0434\u044c \u0442\u0435\u043c, \u0447\u0442\u043e \u0441\u043d\u0438\u043c\u0430\u0435\u0442 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u044c \u0432 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0435 \u043d\u0443\u0436\u043d\u043e\u0439 \u0432\u0435\u0440\u0441\u0438\u0438 PHP \u0441\u043e \u0432\u0441\u0435\u043c\u0438 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u044f\u043c\u0438 \u043d\u0430 \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u0443\u044e \u043c\u0430\u0448\u0438\u043d\u0443. \u041a\u0440\u043e\u043c\u0435 \u0442\u043e\u0433\u043e, \u044d\u0442\u043e \u0435\u0441\u043b\u0438 \u0432 \u0440\u0430\u0437\u043d\u044b\u0445 \u0440\u0435\u043b\u0438\u0437\u0430\u0445 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043b\u0430\u0441\u044c \u0440\u0430\u0437\u043d\u0430\u044f \u0432\u0435\u0440\u0441\u0438\u044f PHP, \u0442\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 Docker\u2019\u0430 \u043e\u0431\u043b\u0435\u0433\u0447\u0430\u0435\u0442 \u0431\u044d\u043a\u043f\u043e\u0440\u0442 \u043f\u0430\u0442\u0447\u0435\u0439 \u0438 \u043f\u0440\u043e\u0433\u043e\u043d \u0442\u0435\u0441\u0442\u043e\u0432 \u0432 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0445 \u0431\u0440\u0430\u043d\u0447\u0430\u0445.<\/p>\n<p>\u041e\u0440\u0433\u0430\u043d\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u0432\u0441\u0435 \u044d\u0442\u043e \u043c\u043e\u0436\u043d\u043e \u0432 \u0432\u0438\u0434\u0435 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e\u0433\u043e Dockerfile\u2019\u0430, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, Dockerfile-test \u0441\u043e \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u043d\u0438\u0435\u043c:<\/p>\n<pre><code>FROM php:7.4-cli  RUN apt-get update \\     &amp;&amp; apt-get install -y libxslt1-dev libzip-dev \\     &amp;&amp; docker-php-ext-install xsl \\     &amp;&amp; docker-php-ext-install intl \\     &amp;&amp; docker-php-ext-install zip \\     &amp;&amp; curl -sS https:\/\/getcomposer.org\/installer | php -- --install-dir=\/usr\/local\/bin --filename=composer<\/code><\/pre>\n<p>\u0414\u0430\u043b\u0435\u0435 \u0441\u043e\u0437\u0434\u0430\u0435\u043c \u0438\u043d\u0441\u0442\u0440\u0443\u043a\u0446\u0438\u0438 \u0434\u043b\u044f Docker Compose (\u0432 \u043c\u043e\u0435\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u0432 \u0444\u0430\u0439\u043b\u0435 docker-compose.test.yml):<\/p>\n<pre><code>version: '3' services:   tests:     build:       context: .       dockerfile: Dockerfile-test     command: bash -c \"cd \/opt\/plesk &amp;&amp; composer install &amp;&amp; composer test\"     volumes:       - .:\/opt\/plesk<\/code><\/pre>\n<p>\u0412 \u0438\u0442\u043e\u0433\u0435 \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442\u0441\u044f \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u0438\u0434\u0438\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0439 \u0437\u0430\u043f\u0443\u0441\u043a \u0442\u0435\u0441\u0442\u043e\u0432:<\/p>\n<pre><code>docker-compose -f docker-compose.test.yml run tests<\/code><\/pre>\n<p>\u0420\u0430\u0437\u043d\u0438\u0446\u0430 \u043f\u043e \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u043c\u0435\u0436\u0434\u0443 \u043c\u0435\u0436\u0434\u0443 \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u044b\u043c \u043f\u0440\u043e\u0433\u043e\u043d\u043e\u043c \u0438 \u043f\u0440\u043e\u0433\u043e\u043d\u043e\u043c \u0432 Docker\u2019\u0435 \u0432 \u043c\u043e\u0435\u043c \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u0441\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 3 \u0440\u0430\u0437\u0430. \u0422\u043e \u0435\u0441\u0442\u044c \u043f\u0440\u0438\u043c\u0435\u0440\u043d\u043e 30 \u0441\u0435\u043a\u0443\u043d\u0434 \u043f\u0440\u043e\u0442\u0438\u0432 10 \u0441\u0435\u043a\u0443\u043d\u0434 \u0434\u043b\u044f \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u043f\u0440\u043e\u0433\u043e\u043d\u0430.<\/p>\n<h2>PhpStorm<\/h2>\n<p>\u0414\u043b\u044f \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u044f PHP \u043a\u043e\u0434\u0430 \u043e\u0431\u044b\u0447\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f <a href=\"https:\/\/www.jetbrains.com\/phpstorm\/\">PhpStorm<\/a>. \u0415\u0441\u0442\u044c \u0432 \u043d\u0435\u043c \u0438 \u0443\u0434\u043e\u0431\u043d\u044b\u0435 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u044b \u043f\u043e \u0440\u0430\u0431\u043e\u0442\u0435 \u0441 PHPUnit.<\/p>\n<p>\u0412\u043e-\u043f\u0435\u0440\u0432\u044b\u0445, \u044d\u0442\u043e \u0437\u0430\u043f\u0443\u0441\u043a \u0442\u0435\u0441\u0442\u043e\u0432, \u0432\u044b\u0431\u0438\u0440\u0430\u044f \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044e \u0438\u0437 \u043c\u0435\u043d\u044e Run (\u0438\u043b\u0438 \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u043d\u043e\u0433\u043e \u043c\u0435\u043d\u044e) phpunit.xml.dist \u0438\u043b\u0438 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u044e, \u0433\u0434\u0435 \u0440\u0430\u0441\u043f\u043e\u043b\u043e\u0436\u0435\u043d\u044b \u0442\u0435\u0441\u0442\u044b. \u041d\u0430\u043a\u043b\u0430\u0434\u043d\u044b\u0435 \u0440\u0430\u0441\u0445\u043e\u0434\u044b \u043d\u0430 \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u0443\u044e \u0432\u0438\u0437\u0443\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e \u0432 PhpStorm \u043d\u0430 \u043c\u043e\u0435\u0439 \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u043e\u0439 \u043c\u0430\u0448\u0438\u043d\u0435 \u0432 \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u043e\u043c \u043f\u0440\u043e\u0435\u043a\u0442\u0435 (~4500 \u0442\u0435\u0441\u0442\u043e\u0432.) \u043f\u043b\u0430\u0432\u0430\u044e\u0442 \u0432 \u0434\u0438\u0430\u043f\u0430\u0437\u043e\u043d\u0435 10-30%, \u043d\u043e \u0432 \u0430\u0431\u0441\u043e\u043b\u044e\u0442\u043d\u044b\u0445 \u0446\u0438\u0444\u0440\u0430\u0445 \u2014 \u044d\u0442\u043e 13 \u0441\u0435\u043a\u0443\u043d\u0434, \u043f\u0440\u043e\u0442\u0438\u0432 10 \u0441\u0435\u043a\u0443\u043d\u0434 \u043f\u0440\u0438 \u0437\u0430\u043f\u0443\u0441\u043a\u0435 \u0432 \u0442\u0435\u0440\u043c\u0438\u043d\u0430\u043b\u0435, \u0447\u0442\u043e \u0441\u043e\u0432\u0435\u0440\u0448\u0435\u043d\u043d\u043e \u043d\u0435\u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0435\u043d\u043d\u043e.<\/p>\n<p>\u0412\u0442\u043e\u0440\u043e\u0439 \u0443\u0434\u043e\u0431\u043d\u044b\u0439 \u043c\u043e\u043c\u0435\u043d\u0442 \u043f\u0440\u0438 \u0438\u043d\u0442\u0435\u043d\u0441\u0438\u0432\u043d\u043e\u0439 \u0440\u0430\u0431\u043e\u0442\u0435 \u0441 \u0442\u0435\u0441\u0442\u0430\u043c\u0438 \u0438 \u0438\u0445 \u0430\u043a\u0442\u0438\u0432\u043d\u043e\u043c \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u0438 \u2014 \u044d\u0442\u043e \u0440\u0435\u0436\u0438\u043c \u201c\u043d\u0430\u0431\u043b\u044e\u0434\u0435\u043d\u0438\u044f\u201d. \u0412\u043a\u043b\u044e\u0447\u0430\u0435\u043c \u0435\u0433\u043e \u0432 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0435\u0439 \u043f\u0430\u043d\u0435\u043b\u0438:<\/p>\n<figure class=\"\"><figcaption><\/figcaption><\/figure>\n<p>\u041f\u043e\u0441\u043b\u0435 \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0431\u0443\u0434\u0435\u0442 \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442\u044c \u043f\u0435\u0440\u0435\u0437\u0430\u043f\u0443\u0441\u043a \u0442\u0435\u0441\u0442\u043e\u0432, \u0430 \u043f\u043e \u0435\u0433\u043e \u043e\u043a\u043e\u043d\u0447\u0430\u043d\u0438\u044e \u2014 \u0432\u0441\u043f\u043b\u044b\u0432\u0430\u0442\u044c \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0435\u0435 \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u0435 \u043e \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0430\u0445 \u043f\u0440\u043e\u0445\u043e\u0436\u0434\u0435\u043d\u0438\u044f.<\/p>\n<p>\u041f\u0440\u0438 \u043d\u0430\u043b\u0438\u0447\u0438\u0438 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u0438\u0445 \u043c\u043e\u043d\u0438\u0442\u043e\u0440\u043e\u0432, \u043e\u0447\u0435\u043d\u044c \u0443\u0434\u043e\u0431\u043d\u043e \u0432\u044b\u043d\u0435\u0441\u0442\u0438 \u043e\u043a\u043d\u043e \u0441 \u0442\u0435\u0441\u0442\u0430\u043c\u0438 \u043d\u0430 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0439 \u043c\u043e\u043d\u0438\u0442\u043e\u0440 \u0438 \u0432\u043a\u043b\u044e\u0447\u0438\u0442\u044c \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0439 \u043f\u0435\u0440\u0435\u0437\u0430\u043f\u0443\u0441\u043a. \u0410 \u0447\u0442\u043e\u0431\u044b \u0442\u0435\u0441\u0442\u044b \u043d\u0435 \u043f\u0435\u0440\u0435\u0437\u0430\u043f\u0443\u0441\u043a\u0430\u043b\u0438\u0441\u044c \u0441\u043b\u0438\u0448\u043a\u043e\u043c \u0447\u0430\u0441\u0442\u043e, \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u0438\u0433\u0440\u0430\u0442\u044c\u0441\u044f \u0441 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u043e\u0439 \u0437\u0430\u0434\u0435\u0440\u0436\u043a\u0438 \u0437\u0430\u043f\u0443\u0441\u043a\u0430:<\/p>\n<figure class=\"\"><figcaption><\/figcaption><\/figure>\n<h2>\u0412\u043d\u0435\u0448\u043d\u0435\u0435 \u043d\u0430\u0431\u043b\u044e\u0434\u0435\u043d\u0438\u0435 \u0437\u0430 \u0442\u0435\u0441\u0442\u0430\u043c\u0438<\/h2>\n<p>\u0424\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b \u201c\u043d\u0430\u0431\u043b\u044e\u0434\u0435\u043d\u0438\u044f\u201d \u0437\u0430 \u0442\u0435\u0441\u0442\u0430\u043c\u0438 \u0432 PhpStorm \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442 \u0443\u0436\u0435 \u0433\u043e\u0434\u0430 3. \u0414\u043e \u044d\u0442\u043e\u0433\u043e \u0437\u0430\u0434\u0430\u0447\u0430 \u0440\u0435\u0448\u0430\u043b\u0430\u0441\u044c \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0432\u043d\u0435\u0448\u043d\u0435\u0433\u043e \u201c\u043d\u0430\u0431\u043b\u044e\u0434\u0430\u0442\u0435\u043b\u044f\u201d. \u041e\u0434\u043d\u0430\u043a\u043e \u0438 \u0441\u0435\u0439\u0447\u0430\u0441 \u043f\u043e \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043d\u044b\u043c \u043f\u0440\u0438\u0447\u0438\u043d\u0430\u043c \u0432\u043d\u0435\u0448\u043d\u0438\u0439 \u201c\u043d\u0430\u0431\u043b\u044e\u0434\u0430\u0442\u0435\u043b\u044c\u201d \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u043f\u043e\u043b\u0435\u0437\u0435\u043d (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0432\u044b \u043f\u0440\u0430\u0432\u0438\u0442\u0435 \u043a\u043e\u0434 \u0432 vim\u2019\u0435 \u0438\u043b\u0438 VSCode).&nbsp;<\/p>\n<p>\u041d\u0430\u0438\u0431\u043e\u043b\u0435\u0435 \u043f\u043e\u043f\u0443\u043b\u044f\u0440\u043d\u044b\u0439 \u0438 \u0436\u0438\u0432\u043e\u0439 \u043f\u0440\u043e\u0435\u043a\u0442 \u043f\u043e \u0434\u0430\u043d\u043d\u043e\u0439 \u0442\u0435\u043c\u0435 \u044d\u0442\u043e <a href=\"https:\/\/github.com\/spatie\/phpunit-watcher\">phpunit-watcher<\/a>. \u0414\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u0435\u0433\u043e \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e composer \u0438 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u043c phpunit-watcher.yml \u043f\u0440\u0438\u043c\u0435\u0440\u043d\u043e \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0433\u043e \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u043d\u0438\u044f:<\/p>\n<pre><code>watch:   directories:     - common\/php     - ...   fileMask: '*.php' phpunit:   binaryPath: common\/php\/plib\/vendor\/bin\/phpunit   arguments: '--stop-on-failure'<\/code><\/pre>\n<p>\u0422\u0430\u043a\u0436\u0435 \u0432 composer.json \u0432 \u0440\u0430\u0437\u0434\u0435\u043b scripts \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u0435\u0449\u0435 \u043e\u0434\u043d\u0443 \u043a\u043e\u043c\u0430\u043d\u0434\u0443:<\/p>\n<pre><code>\"scripts\": {     ...     \"test:watch\": \"phpunit-watcher watch\",     ...<\/code><\/pre>\n<p>\u0422\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c, \u0434\u043b\u044f \u0442\u043e\u0433\u043e, \u0447\u0442\u043e\u0431\u044b \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c \u0442\u0435\u0441\u0442\u044b \u043f\u043e\u0434 \u201c\u043d\u0430\u0431\u043b\u044e\u0434\u0435\u043d\u0438\u0435\u043c\u201d, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u043a\u043e\u043c\u0430\u043d\u0434\u0430 <code>composer test:watch<\/code> \u041e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u043c \u0435\u0435 \u0436\u0438\u0442\u044c \u0432 \u043e\u043a\u043e\u0448\u043a\u043e \u0442\u0435\u0440\u043c\u0438\u043d\u0430\u043b\u0430 \u043d\u0430 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0439 \u043c\u043e\u043d\u0438\u0442\u043e\u0440 \u0438 \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u0443\u0434\u043e\u0431\u0441\u0442\u0432\u043e \u043d\u0430\u0431\u043b\u044e\u0434\u0435\u043d\u0438\u044f, \u0430\u043d\u0430\u043b\u043e\u0433\u0438\u0447\u043d\u043e\u0435 PhpStorm\u2019\u0443.<\/p>\n<h2>\u041a\u043e\u043d\u0442\u0440\u043e\u043b\u044c \u0443\u0440\u043e\u0432\u043d\u044f \u043f\u043e\u043a\u0440\u044b\u0442\u0438\u044f<\/h2>\n<p>\u041f\u0440\u0438 \u0440\u043e\u0441\u0442\u0435 \u043a\u043e\u0434\u043e\u0432\u043e\u0439 \u0431\u0430\u0437\u044b \u0438 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u0430 \u0442\u0435\u0441\u0442\u043e\u0432 \u0432\u043e\u0437\u043d\u0438\u043a\u0430\u0435\u0442 \u0436\u0435\u043b\u0430\u043d\u0438\u0435 \u0443\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0442\u044c code coverage \u0445\u043e\u0442\u044f \u0431\u044b \u043d\u0430 \u0443\u0436\u0435 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0449\u0435\u043c \u0443\u0440\u043e\u0432\u043d\u0435 (\u0430 \u0432 \u0438\u0434\u0435\u0430\u043b\u0435 \u2014 \u0443\u0432\u0435\u043b\u0438\u0447\u0438\u0432\u0430\u0442\u044c \u0435\u0433\u043e). \u041c\u043e\u0436\u043d\u043e \u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0443\u0433\u043e\u0434\u043d\u043e \u043f\u044b\u0442\u0430\u0442\u044c\u0441\u044f \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u044d\u0442\u043e \u0440\u0443\u043a\u0430\u043c\u0438 (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0441\u0438\u043b\u0430\u043c\u0438 \u043a\u0430\u043a\u043e\u0433\u043e-\u0442\u043e \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u043e\u0433\u043e \u0438\u043d\u0436\u0435\u043d\u0435\u0440\u0430), \u0430 \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u0440\u0443\u0447\u0438\u0442\u044c \u044d\u0442\u0443 \u0437\u0430\u0434\u0430\u0447\u0443 \u0440\u043e\u0431\u043e\u0442\u0443. <\/p>\n<p>\u0421\u0445\u0435\u043c\u0430 \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c. \u0421\u043d\u0430\u0447\u0430\u043b\u0430 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u043c \u043f\u043e\u0434\u0441\u0447\u0435\u0442 code coverage, \u0441\u043c\u043e\u0442\u0440\u0438\u043c \u043f\u0440\u043e\u0446\u0435\u043d\u0442 \u043f\u043e\u043a\u0440\u044b\u0442\u0438\u044f \u0438 \u0443\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u043c \u0435\u0433\u043e \u043a\u0430\u043a \u043e\u0442\u043f\u0440\u0430\u0432\u043d\u0443\u044e \u0442\u043e\u0447\u043a\u0443. \u0414\u0430\u043b\u0435\u0435 \u0441\u043e\u0437\u0434\u0430\u0435\u043c \u0441\u043a\u0440\u0438\u043f\u0442, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0431\u0443\u0434\u0435\u0442 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0442\u044c \u043d\u0435\u043d\u0443\u043b\u0435\u0432\u043e\u0439 \u043a\u043e\u0434 \u0432\u043e\u0437\u0432\u0440\u0430\u0442\u0430 (\u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u044f \u043f\u0430\u0434\u0435\u043d\u0438\u0435), \u0435\u0441\u043b\u0438 \u0442\u0435\u043a\u0443\u0449\u0438\u0439 \u043f\u0440\u043e\u0446\u0435\u043d\u0442 code coverage \u0441\u0442\u0430\u043b \u043d\u0438\u0436\u0435 \u043e\u0442\u043f\u0440\u0430\u0432\u043d\u043e\u0439 \u0442\u043e\u0447\u043a\u0438. \u0414\u0430\u043d\u043d\u044b\u0439 \u0441\u043a\u0440\u0438\u043f\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0432 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0430\u0445 \u043d\u0430 pull request\u2019\u0430\u0445, \u0442\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c \u043d\u0435 \u0434\u0430\u0432\u0430\u044f \u0437\u0430\u043c\u0435\u0440\u0436\u0438\u0442\u044c \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f, \u0435\u0441\u043b\u0438 \u043f\u0440\u043e\u0446\u0435\u043d\u0442 code coverage \u0443\u043f\u0430\u043b. \u0414\u043e\u0431\u0430\u0432\u0438\u043b \u043d\u043e\u0432\u044b\u0439 \u043a\u043e\u0434? \u041d\u0443\u0436\u043d\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0442\u0435\u0441\u0442\u044b. \u0421 \u0440\u043e\u0431\u043e\u0442\u043e\u043c-\u0440\u0435\u0432\u044c\u044e\u0432\u0435\u0440\u043e\u043c \u0443\u0436\u0435 \u043d\u0435\u043b\u044c\u0437\u044f \u0434\u043e\u0433\u043e\u0432\u043e\u0440\u0438\u0442\u044c\u0441\u044f, \u043c\u043e\u043b, \u044f \u0447\u0443\u0442\u044c \u043f\u043e\u0437\u0436\u0435 \u0438\u0445 \u0434\u043e\u0431\u0430\u0432\u043b\u044e. \u041e\u043d \u0431\u0435\u0441\u043f\u0440\u0438\u0441\u0442\u0440\u0430\u0441\u0442\u043d\u043e \u043f\u043e\u0441\u0442\u0430\u0432\u0438\u0442 \u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u043a\u0443.<\/p>\n<p>\u0414\u043b\u044f \u043f\u043e\u0434\u0441\u0447\u0435\u0442\u0430 code coverage \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u0435 <a href=\"https:\/\/xdebug.org\/\">Xdebug<\/a>. \u041d\u0430 \u0434\u0430\u043d\u043d\u044b\u0439 \u043c\u043e\u043c\u0435\u043d\u0442, \u043d\u0430 \u0432\u0435\u0440\u0441\u0438\u0438 3.0 \u043d\u0430 \u0432\u0441\u0435\u0445 \u043f\u0440\u043e\u0435\u043a\u0442\u0430\u0445, \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u0441\u043c\u043e\u0442\u0440\u0435\u043b, \u0434\u0435\u043b\u043e \u0437\u0430\u043a\u0430\u043d\u0447\u0438\u0432\u0430\u0435\u0442\u0441\u044f segfault\u2019\u043e\u043c (\u0435\u0441\u0442\u044c \u043a\u0430\u043a \u201c\u043f\u043b\u0430\u0432\u0430\u044e\u0449\u0438\u0435\u201d \u0431\u0430\u0433\u0438, \u0442\u0430\u043a \u0438 \u0441\u0442\u0430\u0431\u0438\u043b\u044c\u043d\u043e \u043f\u043e\u0432\u0442\u043e\u0440\u044f\u0435\u043c\u044b\u0435 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u044b), \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u043f\u0440\u043e\u0434\u043e\u043b\u0436\u0430\u0435\u043c \u043f\u043e\u043a\u0430 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c 2.9.0. \u041f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u044f \u0441 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430\u043c\u0438 \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e (xdebug.mode=develop) \u0434\u0430\u0436\u0435 \u0431\u0435\u0437 \u043f\u043e\u0434\u0441\u0447\u0435\u0442\u0430 code coverage \u043f\u0440\u0438\u0432\u043e\u0434\u0438\u0442 \u043a 2-3 \u043a\u0440\u0430\u0442\u043d\u043e\u043c\u0443 \u0437\u0430\u043c\u0435\u0434\u043b\u0435\u043d\u0438\u044e \u043f\u0440\u043e\u0433\u043e\u043d\u0430 \u0442\u0435\u0441\u0442\u043e\u0432. \u0412 \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u0441 ~4500 \u0442\u0435\u0441\u0442\u0430\u043c\u0438 \u043d\u0430 \u043c\u043e\u0435\u0439 \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u043e\u0439 \u043c\u0430\u0448\u0438\u043d\u0435 \u043f\u0440\u043e\u0446\u0435\u0441\u0441 \u0437\u0430\u043c\u0435\u0434\u043b\u044f\u0435\u0442\u0441\u044f \u0441 10 \u0441\u0435\u043a\u0443\u043d\u0434 \u0434\u043e 27 \u0441\u0435\u043a\u0443\u043d\u0434. \u041f\u043e\u043a\u0430 \u0435\u0449\u0435 \u043d\u0435 \u0441\u0438\u043b\u044c\u043d\u043e \u043a\u0440\u0438\u0442\u0438\u0447\u043d\u043e, \u043d\u043e \u0443\u0436\u0435 \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u0437\u0430\u043c\u0435\u0442\u043d\u043e. \u0415\u0441\u043b\u0438 \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c \u043f\u0440\u043e\u0433\u043e\u043d \u0442\u0435\u0441\u0442\u043e\u0432 \u0432\u043c\u0435\u0441\u0442\u0435 \u0441 \u043f\u043e\u0434\u0441\u0447\u0435\u0442\u043e\u043c code coverage, \u0442\u043e \u043e\u043d \u0437\u0430\u0439\u043c\u0435\u0442 \u0432 \u043c\u043e\u0435\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u0431\u043e\u043b\u044c\u0448\u0435 30 \u043c\u0438\u043d\u0443\u0442. \u0415\u0441\u043b\u0438 \u043f\u0440\u043e\u0446\u0435\u043d\u0442 code coverage \u0443\u043f\u0430\u043b, \u0432\u044b \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u0442\u0435 \u043d\u043e\u0432\u044b\u0435 \u0442\u0435\u0441\u0442\u044b \u0438 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0440\u0430\u0437 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442\u0435 \u0438\u0445 \u043f\u0440\u043e\u0433\u043e\u043d, \u0442\u043e \u0436\u0434\u0430\u0442\u044c \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0440\u0430\u0437 \u043f\u043e 30 \u043c\u0438\u043d\u0443\u0442 \u2014 \u044d\u0442\u043e \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u0434\u043e\u043b\u0433\u043e.<\/p>\n<p>\u0410\u043d\u0430\u043b\u0438\u0437 \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442, \u0447\u0442\u043e \u0431\u043e\u043b\u044c\u0448\u0435 \u0432\u0441\u0435\u0433\u043e \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u0434\u043b\u044f \u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u0438 \u043e\u0442\u0447\u0435\u0442\u0430 \u0432 HTML. \u0422\u0430\u043a \u043a\u0430\u043a \u0441\u0430\u043c \u043e\u0442\u0447\u0435\u0442 \u043d\u0430\u0441 \u043d\u0435 \u043e\u0441\u043e\u0431\u043e \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u0443\u0435\u0442, \u0442\u043e \u043c\u043e\u0436\u043d\u043e \u0432\u043e\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u043e\u043f\u0446\u0438\u0435\u0439 &#8212;coverage-php, \u0430 \u0434\u0430\u043b\u0435\u0435 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u043d\u044b\u0439 \u0444\u0430\u0439\u043b \u043f\u0440\u043e\u0430\u043d\u0430\u043b\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u043c \u0441\u043a\u0440\u0438\u043f\u0442\u043e\u043c. \u0412 \u0438\u0442\u043e\u0433\u0435 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u0442\u0435\u043a\u0443\u0449\u0435\u0433\u043e \u043f\u0440\u043e\u0446\u0435\u043d\u0442\u0430 code coverage \u0438\u0437 30 \u043c\u0438\u043d\u0443\u0442 \u043f\u0440\u0435\u0432\u0440\u0430\u0449\u0430\u0435\u0442\u0441\u044f \u0432 2 \u043c\u0438\u043d\u0443\u0442\u044b \u043d\u0430 \u043f\u0440\u043e\u0433\u043e\u043d \u0442\u0435\u0441\u0442\u043e\u0432 \u0438 \u0435\u0449\u0435 \u043f\u0440\u0438\u043c\u0435\u0440\u043d\u043e 2,5 \u043c\u0438\u043d\u0443\u0442\u044b \u043d\u0430 \u0430\u043d\u0430\u043b\u0438\u0437 \u0440\u0435\u043f\u043e\u0440\u0442\u0430 (\u043d\u0430\u043f\u043e\u043c\u043d\u044e, \u0447\u0442\u043e \u043f\u0440\u043e\u0435\u043a\u0442 \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u0431\u043e\u043b\u044c\u0448\u043e\u0439, \u0438 \u0444\u0430\u0439\u043b \u0437\u0430\u043d\u0438\u043c\u0430\u0435\u0442 \u0431\u043e\u043b\u0435\u0435 60 \u041c\u0431). \u0415\u0441\u0442\u044c \u0435\u0449\u0435 \u043f\u043e\u043b\u0435 \u0434\u043b\u044f \u043e\u043f\u0442\u0438\u043c\u0438\u0437\u0430\u0446\u0438\u0438, \u043d\u043e \u0442\u0435\u043a\u0443\u0449\u0438\u0439 \u0432\u0430\u0440\u0438\u0430\u043d\u0442 \u0443\u0436\u0435 \u0443\u0441\u0442\u0440\u0430\u0438\u0432\u0430\u0435\u0442. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0441\u043e\u043a\u0440\u0430\u0442\u0438\u0442\u044c \u043f\u0435\u0440\u0432\u0443\u044e \u0444\u0430\u0437\u0443 \u0441 2 \u043c\u0438\u043d\u0443\u0442 \u0434\u043e 1 \u043c\u0438\u043d\u0443\u0442\u044b \u043c\u043e\u0436\u043d\u043e \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e <a href=\"https:\/\/github.com\/krakjoe\/pcov\">pcov<\/a>.<\/p>\n<p>\u0412 phpunit.dist.xml \u043d\u0443\u0436\u043d\u043e \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u0442\u044c\u0441\u044f \u0441 \u0441\u0435\u043a\u0446\u0438\u0435\u0439 coverage. \u0422\u0430\u043a\u0436\u0435 \u0432\u0430\u0436\u043d\u043e \u0443\u043a\u0430\u0437\u0430\u0442\u044c \u043e\u043f\u0446\u0438\u044e includeUncoveredFiles, \u043f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e \u043f\u0440\u043e\u0446\u0435\u043d\u0442 \u043f\u043e\u043a\u0440\u044b\u0442\u0438\u044f \u043d\u0443\u0436\u043d\u043e \u0441\u0447\u0438\u0442\u0430\u0442\u044c \u043e\u0442 \u0432\u0441\u0435\u0445 \u0444\u0430\u0439\u043b\u043e\u0432, \u0430 \u043d\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u0442\u0435\u0445, \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u201c\u043a\u0430\u0441\u0430\u043b\u0438\u0441\u044c\u201d \u0442\u0435\u0441\u0442\u044b.<\/p>\n<pre><code class=\"xml\"> &lt;coverage includeUncoveredFiles=\"true\"&gt;     &lt;include&gt;       &lt;directory suffix=\".php\"&gt;common\/php&lt;\/directory&gt;       ...     &lt;\/include&gt;     &lt;exclude&gt;       &lt;directory&gt;common\/php\/plib\/locales&lt;\/directory&gt;       &lt;directory&gt;common\/php\/plib\/vendor&lt;\/directory&gt;       &lt;directory&gt;common\/php\/tests&lt;\/directory&gt;       ...     &lt;\/exclude&gt;   &lt;\/coverage&gt;<\/code><\/pre>\n<p>\u0412 composer.json \u0444\u043e\u0440\u043c\u0438\u0440\u0443\u0435\u043c \u043a\u043e\u043c\u0430\u043d\u0434\u0443 \u0434\u043b\u044f \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u0441 \u0443\u0447\u0435\u0442\u043e\u043c \u0432\u0441\u0435\u0433\u043e \u0432\u044b\u0448\u0435\u0441\u043a\u0430\u0437\u0430\u043d\u043d\u043e\u0433\u043e:<\/p>\n<pre><code class=\"json\"> \"scripts\": {     ...     \"test-coverage-threshold\": [       \"@php -dzend_extension=xdebug.so -dxdebug.mode=coverage common\/php\/plib\/vendor\/bin\/phpunit --coverage-php .phpunit.coverage.php\",       \"@php -dzend_extension=xdebug.so common\/tools\/coverage-threshold.php .phpunit.coverage.php 12.49\"     ],     ...<\/code><\/pre>\n<p>\u0413\u0434\u0435 \u043c\u0430\u0433\u0438\u0447\u0435\u0441\u043a\u0430\u044f \u0446\u0438\u0444\u0440\u0430 12.49 \u2014 \u044d\u0442\u043e \u0442\u0435\u043a\u0443\u0449\u0430\u044f \u043e\u0442\u043f\u0440\u0430\u0432\u043d\u0430\u044f<\/p>\n<\/div>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-322099","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/322099","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=322099"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/322099\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=322099"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=322099"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=322099"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}