How to Avoid –stderr When Running phpunit for Functional/Integration Testing
When you do a Functional/Integration test with session and/or header relation. It will force you to use --stderr
when running phpunit, or it will got error, eg: you’re testing that on logout when session exists as user, page will be redirected to login page with status code 302, and it got the following error:
$ vendor/bin/phpunit test/Integration/LogoutPageTest.php PHPUnit 8.5.2 by Sebastian Bergmann and contributors. Logout Page (AppTest\Integration\LogoutPage) ✘ Open logout page as auser redirect to login page ┐ ├ Failed asserting that 500 matches expected 302. │ ╵ /Users/samsonasik/www/mezzio-authentication-with-authorization/test/Integration/LogoutPageTest.php:36 ┴ Time: 155 ms, Memory: 10.00 MB FAILURES! Tests: 1, Assertions: 1, Failures: 1.
You can use --stderr
option on running it:
$ vendor/bin/phpunit test/Integration/LogoutPageTest.php --stderr PHPUnit 8.5.2 by Sebastian Bergmann and contributors. Logout Page (AppTest\Integration\LogoutPage) √ Open logout page as auser redirect to login page Time: 150 ms, Memory: 8.00 MB OK (1 test, 2 assertions)
or define stderr=true
in phpunit.xml
configuration:
<?xml version="1.0" encoding="UTF-8"?> <phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="vendor/phpunit/phpunit/phpunit.xsd" bootstrap="vendor/autoload.php" colors="true" testdox="true" stderr="true"> <!-- testsuites, filter, etc config --> </phpunit>
Marking all test to be using stderr
is a workaround, as not all tests actually require that, eg: unit test doesn’t need that. To avoid it, we can define @runTestsInSeparateProcesses
and @preserveGlobalState disabled
in the controller class that require that, so, the test class will be like the following:
<?php declare(strict_types=1); namespace AppTest\Integration; use Laminas\Diactoros\ServerRequest; use Laminas\Diactoros\Uri; use Mezzio\Authentication\UserInterface; use PHPUnit\Framework\TestCase; /** * @runTestsInSeparateProcesses * @preserveGlobalState disabled */ class LogoutPageTest extends TestCase { private $app; protected function setUp(): void { $this->app = AppFactory::create(); } public function testOpenLogoutPageAsAuserRedirectToLoginPage() { $sessionData = [ 'username' => 'samsonasik', 'roles' => [ 'user', ], ]; $_SESSION[UserInterface::class] = $sessionData; $uri = new Uri('/logout'); $serverRequest = new ServerRequest([], [], $uri); $response = $this->app->handle($serverRequest); $this->assertEquals(302, $response->getStatusCode()); $this->assertEquals('/login', $response->getHeaderLine('Location')); } }
That’s it!
Publish Test Coverage to Codecov from Github Actions
Github Actions is one of ways to run Continues Integration. For Coverage report, we can use Codecov to publish the coverage result after running and generating test coverage.
For example, you have a Github Repository. You can open https://codecov.io/login and choose “Github”:
After you logged in, you can choose repository, or directly access https://codecov.io/gh/{your github user}/{your github repo}, for example, I use “samsonasik” as user, and “mezzio-authentication-with-authorization” as repository name:
https://codecov.io/gh/samsonasik/mezzio-authentication-with-authorization
On very first, we need to activate Webhook by open https://codecov.io/gh/gh/{your github user}/{your github repo}/settings, for example:
https://codecov.io/gh/samsonasik/mezzio-authentication-with-authorization/settings
Then, we click “Create new webhook” under Github Webhook:
After it done, we can copy “Repository Upload Token”:
by click “Copy” after then token, and back to Github, and save to Secrets section under Your Github Repository Settings with click “Add a new secret”, with eg: named: CODECOV_TOKEN, fill the value with your copied token, and click “Add secret” to save it to be like as follow:
The preparation is done. Now, time to add the github workflow, eg: “.github/workflows/ci-build.yml” at your repository, eg for php package/project and use phpunit, the workflow can be like the following:
name: "ci build" on: pull_request: push: branches: - "master" jobs: build: name: PHP ${{ matrix.php-versions }} runs-on: ubuntu-latest strategy: fail-fast: false matrix: php-versions: ['7.2', '7.3', '7.4'] steps: - name: Setup PHP Action uses: shivammathur/setup-php@1.8.2 with: extensions: intl php-version: "${{ matrix.php-versions }}" coverage: pcov - name: Checkout uses: actions/checkout@v2 - name: "Validate composer.json and composer.lock" run: "composer validate" - name: "Install dependencies" run: "composer install --prefer-dist --no-progress --no-suggest && composer development-enable" - name: "Run test suite" run: "vendor/bin/phpunit --coverage-clover=coverage.xml" - name: Upload coverage to Codecov uses: codecov/codecov-action@v1 with: token: ${{ secrets.CODECOV_TOKEN }} file: ./coverage.xml flags: tests name: codecov-umbrella yml: ./codecov.yml fail_ci_if_error: true
That’s it. To trigger the Continues Integration, we can push a commit to the repository.
When its succeed (ci build green), we can then display coverage badge, eg at README.md like the following:
[](https://codecov.io/gh/{your github user}/{your github repo})
that will show:
leave a comment