Suppress symfony 4 response body in phpunit test - phpunit

I am migrating a Silex app to Symfony Flex and everything is working so far, except that when I run the phpunit tests I get the response body output into the phpunit output.
ie.
> bin/phpunit
#!/usr/bin/env php
PHPUnit 6.5.13 by Sebastian Bergmann and contributors.
Testing unit
.......<http://data.nobelprize.org/resource/laureate/914> a <http://data.nobelprize.org/terms/Laureate> , <http://xmlns.com/foaf/0.1/Person> ;
<http://www.w3.org/2000/01/rdf-schema#label> "Malala Yousafzai" ;
<http://data.nobelprize.org/terms/laureateAward> <http://data.nobelprize.org/resource/laureateaward/974> ;
<http://data.nobelprize.org/terms/nobelPrize> <http://data.nobelprize.org/resource/nobelprize/Peace/2014> ;
the entire RDF document then
. 8 / 8 (100%)
Time: 1.07 seconds, Memory: 14.00MB
OK (8 tests, 71 assertions)
Generating code coverage report in Clover XML format ... done
So it is working fine, but I can't figure out how to disable this output?
The request is simply
$this->client->request('GET', "/nobel_914.ttl", [], [], ['HTTP_ACCEPT' => $request_mime]);
$this->assertEquals(200, $this->client->getResponse()->getStatusCode(), "GET should be allowed.");
$response = $this->client->getResponse();
$charset = $response->getCharset();
etc.
and the client is setup in a base class like this
class MyAppTestBase extends WebTestCase
{
/**
* #var \Symfony\Component\BrowserKit\Client
*/
protected $client;
/**
* {#inheritdoc}
*/
public function setUp() {
parent::setUp();
$this->client = static::createClient();
$this->client->catchExceptions(false);
}
I'm sure I'm missing something obvious but this is new to me. I am running in the 'test' environment and with 'debug' == false.
Any help appreciated.

So this was probably a problem all along but just started being exposed in the switch from Silex to Symfony Flex.
We were streaming responses via
$filename = $this->path;
$stream = function () use ($filename) {
readfile($filename);
};
return new StreamedResponse($stream, 200, $res->headers->all());
and the readfile was throwing the content to the output buffer. Switching the readfile to file_get_contents resolved this
$filename = $this->path;
$stream = function () use ($filename) {
file_get_contents($filename);
};
return new StreamedResponse($stream, 200, $res->headers->all());

Related

You have requested a non-existent service "test.service_container". Did you mean this: "service_container"?

PHPUnit 7.5.15 by Sebastian Bergmann and contributors.
Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException : You have requested a non-existent service "test.service_container". Did you mean this: "service_container"?
/opt/project/backend/vendor/symfony/symfony/src/Symfony/Component/DependencyInjection/Container.php:277
/opt/project/backend/vendor/symfony/symfony/src/Symfony/Component/DependencyInjection/Container.php:225
/opt/project/backend/tests/Functional/KernelAwareTest.php:49
/opt/project/backend/tests/Functional/FlightTaskManagement/AssignEmployeeToTaskTest.php:47
public function setUp(): void
{
global $kernel;
$this->kernel = TestKernel::get();
$kernel = $this->kernel;
$container = $this->kernel->getContainer();
if ($container === null)
throw new \InvalidArgumentException('Container can not be null.');
$this->container = $container->get('test.service_container');
// $this->container = $container->get('service_container');
/** #var Registry $doctrine */
$doctrine = $this->container->get('doctrine');
/** #var \Doctrine\ORM\EntityManager $manager */
$manager = $doctrine->getManager();
$this->entityManager = $manager;
$this->entityManager->beginTransaction();
if (!$this->container->initialized(WorkDistributionTransport::class)) {
$this->container->set(WorkDistributionTransport::class, new InMemoryTransport());
}
if (!$this->container->initialized(Configuration::class)) {
$this->container->set(Configuration::class, new TestConfiguration());
}
parent::setUp();
}
It fails at line
$this->container = $container->get('test.service_container');
Symfony is 4.1 but looks like not finished to update. I can't remember by what we decided that it was not finished to update from earlier version.
Not clear if that is the problem that it is not finished to update. Looks like in 4.0 there is no such service so thats why. But then how to make it appear here?
Or maybe I can use
$this->container = $container->get('service_container');
as with earlier versions? Just what is faster way?
I just tried using
$this->container = $container->get('service_container');
but I then get
Doctrine\DBAL\DBALException : An exception occured while establishing a connection to figure out your platform version.
You can circumvent this by setting a 'server_version' configuration value
But I had set the version in config_test.yml so not clear which way is faster to fix.
doctrine:
dbal:
server_version: 5.7
driver: pdo_mysql
host: db_test
port: null
dbname: project
user: project
password: project
Probably if I load service_container then it does not load test config and thats why I get this server_version error. So then need to somehow make it load test config.
Found: I had hardcoded dev environment in AppKernel. Probably thats why I was getting this error. Hardcoding test env fixed. Would be good somehow to make it without hardcoding, but it is still better than nothing:
public function __construct($environment, $debug)
{
// $environment ='dev';
$environment ='test';
$debug= true;
parent::__construct($environment, $debug);
date_default_timezone_set('UTC');
}

behat 3 mink testing redirection

In symfony 3 controller file I have function:
/**
* #Route("/user/registration", name="post_registration")
* #Method("POST")
* #return mixed
*/
public function postRegistration()
{
$post = $this->getAllPost();
$this->curl = $this->get('ApiClient');
$responseArray = $this->curl->post(
$this->container->getParameter('api_url') . '/users',
$post
);
if (isset($responseArray['api_key'])) {
return $this->redirectResponseWithCookie($responseArray['api_key']);
} else {
return $this->render(
static::REGISTRATION_TEMPLATE,
['errors' => $responseArray['errors']]
);
}
}
In one part it calls function
redirectResponseWithCookie()
which should redirect the page.
I want to test redirection header - does it have the right Location value.
I have function in UserRegistrationContext class
class UserRegistrationContext extends BaseContext implements Context, SnippetAcceptingContext
{
/**
* #When I register successfully into the system
* #return null
*/
public function iRegisterSuccessfullyIntoTheSystem()
{
$this->canIntercept();
$this->session->getDriver()->getClient()->followRedirects(false);
// Enters his data
// Posts to www.notification.guru .
$this->session->getDriver()->getClient()
->request('POST', $this->baseUrl . '/user/registration', $this->getFormArray());
echo 'test';
}
}
BaseContext class just has some helper functions, its contructor inits session:
$driver = new GoutteDriver();
$this->session = new Session($driver);
this part might be wrong:
$this->session->getDriver()->getClient()->followRedirects(false);
I just took code from behat 2.5 and tried to adjust to work it with behat 3, but not sure if its correct, but at least does not throw error.
It should stop redirect, so then I could get a response header with
getResponseHeaders()
But the problem is that it tries to redirect, and code fails, because real site is not lauched yet where it redirects. And also I would not be able to test headers I guess after real redirection.
So the redirection has to be stopped I guess.
How to do that? I cannot find info.
Test fails at line
$this->session->getDriver()->getClient()
->request('POST', $this->baseUrl . '/user/registration', $this->getFormArray());
So code in my question is not wrong, as I said in comment - I did not see well in console. Often happens that when I post to SO, I do not even finish writing the question, just from writing the details to others I see the answer.
$this->session->getDriver()->getClient()->followRedirects(false);
works well.
So to finish how to check - make function something like this and call it:
/**
* #param Behat\Mink\Session $session - mink session
* #throws \Exception
* #return null
*/
public function isLoggedIntoApi($session)
{
$headers = $session->getResponseHeaders();
if ($headers['Location'][0] != $this->appUrl) {
throw new \Exception(
'User is not redirected to ' . $this->appUrl
);
}
}

PHPUnit -setUp() - does it run before and after each test case?

I am still a bit confused with setup() in PHPUnit.
Does it run before and after each test case?
For intance, I want to clean up my article table before each test but I want to keep the test data that I already injected into the table. Because I only want to clean it until the next test.
My test,
namespace Test\Foo\Article;
use Test\SuiteTest;
use Foo\Article;
class ArticleTest extends SuiteTest
{
protected static $Article;
/**
* Call this template method before each test method is run.
*/
protected function setUp()
{
$this->truncateTables(
[
'article'
]
);
self::$Article = new Article(self::$PDO);
}
public function testFetchRow()
{
self::$Article->createRow(
[
':title' => 'Hello World',
':description' => 'Hello World',
':content' => 'Hello World'
]
);
$result = self::$Article->fetchRow(
[
':article_id' => self::$PDO->fetchLastInsertId()
]
);
$this->assertArrayHasKey('article_id', $result);
$expected = 12; // 12 keys associate with values in the array
$this->assertEquals($expected, count($result));
}
}
I check my article table, there is no test data anymore, it seems that setup() has cleaned it up. Is it how it should work?
What about the tearDown() - does it mean to run after the each test case?
setUp() runs before every single test method, tearDown() runs after each test method.
PHPUnit Manual - Chapter 4 Fixures:
Before a test method is run, a template method called setUp() is invoked
...
Once the test method has finished running, whether it succeeded or failed, another template method called tearDown() is invoked
See https://phpunit.de/manual/current/en/fixtures.html

symfony test database insert

I have a functional test that creates and persists some things in the database and I want to test that the correct number of items was inserted (there is a scenario where it currently inserts two instead of one).
In the controller everything seems to work and if I use the code below (in the controller) to debug it, I get the expected (wrong) value of "2":
$em = $this->getDoctrine()->getManager();
$fooRepo = $em->getRepository('CompanyProjectBundle:Foo');
$foos = $fooRepo->retrieveByBar(3);
echo count($foos); // Gives a result of 2
However, if I try something similar from within my Test class I get zero...
/**
* {#inheritDoc}
*/
protected function setUp()
{
static::$kernel = static::createKernel();
static::$kernel->boot();
$this->em = static::$kernel->getContainer()
->get('doctrine')
->getManager()
;
$this->em->getConnection()->beginTransaction();
}
/**
* {#inheritDoc}
*/
protected function tearDown()
{
parent::tearDown();
$this->em->getConnection()->rollback();
$this->em->close();
}
public function testFooForm()
{
// ... do some testing
$fooRepo = $this->em->getRepository('CompanyProjectBundle:Foo');
$foos = $fooRepo->retrieveByBar(3);
echo count($foos); // gives a result of ZERO
// ... more happens later
}
Is it getting a different entity manager or something like that? Should I be using some other method to get hold of the correct EM so I can then view the same data that the app is running from?
Everything's running inside a transaction (which is rolled back when the test client is destroyed), but that happens after the snippet shown above.
Ah... solved my own problem. I think I was getting the wrong EntityManager. I fixed it by getting the EntityManager via the client's container instead of the kernel's one:
public function testFooForm()
{
// ... do some testing
$clientEm = $client->getContainer()->get('doctrine.orm.entity_manager');
$fooRepo = $clientEm->getRepository('CompanyProjectBundle:Foo');
$foos = $fooRepo->retrieveByBar(3);
echo count($foos); // gives the correct result of 2
// ... more happens later
}

How to catch PHP Warning in PHPUnit

I am writing test cases and here is a question I have.
So say I am testing a simple function someClass::loadValue($value)
The normal test case is easy, but assume when passing in null or -1 the function call generates a PHP Warning, which is considered a bug.
The question is, how do I write my PHPUnit test case so that it succeeds when the functions handles null/-1 gracefully, and fail when there is a PHP Warning thrown?
PHPUnit_Util_ErrorHandler::handleError() throws one of several exception types based on the error code:
PHPUnit_Framework_Error_Notice for E_NOTICE, E_USER_NOTICE, and E_STRICT
PHPUnit_Framework_Error_Warning for E_WARNING and E_USER_WARNING
PHPUnit_Framework_Error for all others
You can catch and expect these as you would any other exception.
/**
* #expectedException PHPUnit_Framework_Error_Warning
*/
function testNegativeNumberTriggersWarning() {
$fixture = new someClass;
$fixture->loadValue(-1);
}
I would create a separate case to test when the notice/warning is expected.
For PHPUnit v6.0+ this is the up to date syntax:
use PHPUnit\Framework\Error\Notice;
use PHPUnit\Framework\Error\Warning;
use PHPUnit\Framework\TestCase;
class YourShinyNoticeTest extends TestCase
{
public function test_it_emits_a_warning()
{
$this->expectException(Warning::class);
file_get_contents('/nonexistent_file'); // This will emit a PHP Warning, so test passes
}
public function test_it_emits_a_notice()
{
$this->expectException(Notice::class);
$now = new \DateTime();
$now->whatever; // Notice gets emitted here, so the test will pass
}
}
What worked for me was modifying my phpunit.xml to have
<phpunit
convertErrorsToExceptions="true"
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
strict="true"
>
</phpunit>
The key was to use strict="true" to get the warnings to result in a failed test.
You can also write a phpunit.xml file (on your tests dir) with this:
<phpunit
convertErrorsToExceptions="true"
convertNoticesToExceptions="false"
stopOnFailure="false">
</phpunit>
Using Netsilik/BaseTestCase (MIT License) you can test directly for triggered Errors/Warnings, without converting them to Exceptions:
composer require netsilik/base-test-case
Testing for an E_USER_NOTICE:
<?php
namespace Tests;
class MyTestCase extends \Netsilik\Testing\BaseTestCase
{
/**
* {#inheritDoc}
*/
public function __construct($name = null, array $data = [], $dataName = '')
{
parent::__construct($name, $data, $dataName);
$this->_convertNoticesToExceptions = false;
$this->_convertWarningsToExceptions = false;
$this->_convertErrorsToExceptions = true;
}
public function test_whenNoticeTriggered_weCanTestForIt()
{
$foo = new Foo();
$foo->bar();
self::assertErrorTriggered(E_USER_NOTICE, 'The warning string');
}
}
Hope this helps someone in the future.
public function testFooBar(): void
{
// this is required
$this->expectWarning();
// these are optional
$this->expectWarningMessage('fopen(/tmp/non-existent): Failed to open stream: No such file or directory');
$this->expectWarningMessageMatches('/No such file or directory/');
fopen('/tmp/non-existent', 'rb');
}
Make SomeClass throw an error when input is invalid and tell phpUnit to expect an error.
One method is this:
class ExceptionTest extends PHPUnit_Framework_TestCase
{
public function testLoadValueWithNull()
{
$o = new SomeClass();
$this->setExpectedException('InvalidArgumentException');
$this->assertInstanceOf('InvalidArgumentException', $o::loadValue(null));
}
}
See documentation for more methods.

Resources