Symfony and PhpUnit memory leak - symfony

We have issues with memory leak when loading Doctrine in our phpunit tests
Starting for Symfony's documentation :
http://symfony.com/doc/2.7/cookbook/testing/doctrine.html we have written this test :
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
class memoryleakTest extends KernelTestCase
{
private $em;
protected function setUp()
{
self::bootKernel();
$this->em = static::$kernel->getContainer()
->get('doctrine')
->getManager();
}
protected function tearDown()
{
parent::tearDown();
$this->em->close();
}
function testEEE1() {
}
function testEEE2() {
}
function testEEE3() {
}
function testEEE4() {
}
function testEEE5() {
}
function testEEE6() {
}
function testEEE7() {
}
function testEEE8() {
}
function testEEE9() {
}
function testEEE10() {
}
function testEEE11() {
}
function testEEE12() {
}
function testEEE13() {
}
function testEEE14() {
}
function testEEE15() {
}
function testEEE16() {
}
}
we got this result (php_memory_usage between parenthesis) :
testEEE1: . (42M)
testEEE2: . (42.7M)
testEEE3: . (43.3M)
testEEE4: . (44M)
testEEE5: . (44.8M)
testEEE6: . (45.5M)
testEEE7: . (46.1M)
testEEE8: . (46.8M)
testEEE9: . (47.4M)
testEEE10: . (48.1M)
testEEE11: . (48.7M)
testEEE12: . (49.4M)
testEEE13: . (50.1M)
testEEE14: . (50.7M)
testEEE15: . (51.4M)
testEEE16: . (52M)
If we remove the doctrine manager loading in setup, we got (32,7M) for each test
Is it a proper way to unload doctrine after each test in the teardown function ?

The full solution as been found here:
https://github.com/symfony/symfony/issues/18236
For each service used in the phpunit test, you have to free it by assigning null to the variable if you want the garbage collector to free memory.
protected function tearDown()
{
parent::tearDown();
$this->em->close();
$this->em=null;
gc_collect_cycles();
}

To make this even easier for you, you can have a BaseTestCase.php with a teardown function and put this inside:
// Remove properties defined during the test
$refl = new \ReflectionObject($this);
foreach ($refl->getProperties() as $prop) {
if (!$prop->isStatic() && 0 !== strpos($prop->getDeclaringClass()->getName(), 'PHPUnit_')) {
$prop->setAccessible(true);
$prop->setValue($this, null);
}
}
That piece of code will save you from some headaches :)

Related

Phpunit, test code or tested code did not (only) close its own output buffers

I have a code to test:
class ToTest
{
public function testMe()
{
echo 'test';
}
}
class TestTest extends \PHPUnit\Framework\TestCase
{
public function testX()
{
ob_start();
(new ToTest())->testMe();
$c = ob_get_clean();
$this->assertSame('test', $c);
}
}
this passes but marked as risky test:
Test code or tested code did not (only) close its own output buffers
to me, it looks I handled output buffering well...
There must be some code under test interfering with the buffer. For example, if the code under test opens a buffer and doesn't close it for some reason, then you will end up with an open buffer.
The following will cause the a risky test:
class ToTest
{
public function testMe(): void
{
ob_start(); // buffer is never closed
echo 'test';
}
}
final class FizzTest extends TestCase
{
public function testObjectBuffer(): void
{
ob_start();
(new ToTest())->testMe();
$c = ob_get_clean();
$this->assertSame('test', $c);
}
}
The first thing to do is use the PHPUnit output testing assertions:
public function testObjectBuffer(): void
{
$this->expectOutputString('test');
(new ToTest())->testMe();
}
Once you do that, you will know for sure that the code under test is opening a buffer somewhere and not closing it.

Determine if block has already been registered

In gutenberg/block-editor, how can I check whether I've already registered a block type? Is there a function I can use? Searching through the Block Editor Handbook I couldn't see a function to check this.
An example of what I am trying to do is below:
class My_Block {
public function __construct() {
if ( ! SOME_FUNCTION_block_exists('foo/column') ) {
register_block_type( 'foo/column', my_args );
}
}
}
In WordPress Gutenberg, using JavaScript you can check if a block exists by name with getBlockType(), eg:
JavaScript
import { getBlockType } from '#wordpress/blocks';
import { registerBlockType } from '#wordpress/blocks';
if (!getBlockType('foo/column')) {
registerBlockType('foo/column', {
edit: Edit,
save,
});
}
While the above is probably the prefered way, there is a valid case for checking in PHP if a block is already registered, eg. if you want to add a render callback for a block with server side rendering. While I haven't seen a core function for this, I've found a way it can be done by using the REST API endpoint for block-types to search for the block by namespace/name:
PHP
class My_Block
{
public function __construct()
{
if (! is_block_registered('foo/column')) {
register_block_type('foo/column', $args);
}
}
private function is_block_registered($block_name)
{
// Use REST API to query if block exists by <namespace>/<name>
$route = new WP_REST_Request('GET', '/wp/v2/block-types/' . $block_name);
$request = rest_do_request($route);
if ($request->status == 404) {
// Block is not found/registered
return false;
}
// Block is registered (status is 200)
return true;
}
}
There is the method ´is_registered()´ in the class ´WP_Block_Type_Registry´ (that class handles the registration of blocks). See the docs: https://developer.wordpress.org/reference/classes/wp_block_type_registry/is_registered/
class My_Block {
public function __construct() {
if ( ! WP_Block_Type_Registry::get_instance()->is_registered( 'foo/column' ) ) {
register_block_type( 'foo/column', my_args );
}
}
}

Testing console command that uses kernel.terminate event (KernelTestCase)

I want to test a symfony 4 console command.
Importantly, I want to test the situation after all kernel.terminate eventlisteners have finished. To demonstrate here, I have a most simple listener that var_dumps a string:
class NotificationCenter implements EventSubscriberInterface
{
public function onException()
{
$this->wasExceptionThrown = true;
}
public function onTerminate()
{
if ($this->wasExceptionThrown) {
return;
}
var_dump("Hiho from terminate");
}
public static function getSubscribedEvents()
{
$listeners = [
KernelEvents::EXCEPTION => ['onException', 1024],
KernelEvents::TERMINATE => ['onTerminate', 1024],
];
if (class_exists('Symfony\Component\Console\ConsoleEvents')) {
$listeners[class_exists('Symfony\Component\Console\Event\ConsoleErrorEvent') ? ConsoleEvents::ERROR : ConsoleEvents::EXCEPTION] = ['onException', 1024];
$listeners[ConsoleEvents::TERMINATE] = ['onTerminate', 1024];
}
return $listeners;
}
public function reset()
{
$this->wasExceptionThrown = false;
}
}
So, with this eventlistener enabled, any call to any command (or http route) outputs this string.
According to the docs, I have created a Test case:
class MissingDataNotifyCommandTest extends KernelTestCase
{
protected function setUp()
{
self::bootKernel();
}
public function testHiHoIsThere()
{
$application = new Application(static::$kernel);
$command = $application->find('debug:event-dispatcher');
$commandTester = new CommandTester($command);
$commandTester->execute(['command' => $command->getName()]);
$this->assertContains('Hiho from terminate', $commandTester->getDisplay());
}
}
But the assertion fails. Funny enough, the debug command that var_dumps is listed under kernel.terminate.
How can I make sure the kernel.terminate eventlisteners are dispatched during a KernelTestCase?
Edit: my solution
Ok, with Tomas Votruba's help, I was able to find a (partial) solution:
class MissingDataNotifyCommandTest extends KernelTestCase
{
protected function setUp()
{
self::bootKernel();
}
public function testHiHoIsThere()
{
$application = new Application(static::$kernel);
$application->setAutoExit(false);
$application->setCatchExceptions(false);
$stringInput = ['debug:event-dispatcher'];
$input = new StringInput(implode(' ', $stringInput));
$application->run($input, new NullOutput());
}
}
The only problem I could not solve was to get the output of the command back into my code. Moreover, this somehow does run some framework/container code twice (once when booting the kernel inside the tests, once when executing the command).
I double checked and it looks like you're testing Console, not Kernel. They're 2 different classes.
Kernel terminate event is invoked here.
Console Application "terminate" event is invoked here.
Try adding console terminate event to subscriber - console.terminate.
class YourSubscriber implements EventSubccriberInterface
{
public static function getSubscribedEvents()
{
return [
KernelEvents::TERMINATE => 'someFunction',
ConsoleEvents::TERMINATE => 'someFunction',
];
}
public function someFunction()
{
}
}

PHPUnit 5.1.3: assertEquals() not working. Error: No tests executed

I need to compare two arrays in phpunit. I am using asserequals() but output shows No Tests Executed! I am mentioning my arrays below and code too:
$expected_arr = array('success' => 1);
$result_array =(output of print_r($result_array))
Array
(
[success] => 1
)
$this->assertEquals($arr_data,$expected_arr);
My PHPUnit version is 5.1.3. I am running is on Ubuntu 16
UPDATED:
<?php
require_once ('PHPUnit/Framework/TestCase.php');
class abc_auto_testing_test extends PHPUnit_Framework_TestCase
{
public $abc_id;
public $abc_answer;
public function __construct($ABC_id, $ABC_answer)
{
$this->abc_id = $ABC_id;
$this->abc_answer = $ABC_answer;
$this->test_Abc_Validate($this->abc_id, $this->abc_answer);
}
public function setUp()
{
}
public function tearDown()
{
}
public function test_Abc_Validate($abcId, $abcAnswer)
{
$expected_arr = array('success' => 1);
// var_dump($expected_arr);
$arr_data = ABC_Validate($abcId, $abcAnswer);
// var_dump($arr_data);
$this->assertEquals($arr_data,$expected_arr);
}
}
require'/var/www/data.abc.in/abc_server_crons/abc_auto_testing_bkp.php';
$ABC_identifier = $abcIdentifier;
$ABC_answer = $abcAnswer;
$validObj = new abc_auto_testing_test($ABC_identifier, $ABC_answer);
?>
Your test code makes no sense. Go here to learn the basics of writing and running tests.

Override functions.php in Wordpress

I am new to Wordpress and I am trying to override functions.php, with my functions.php file in my Child Theme. The original code I wanna change is
function generic_read_more_link() {
if (!is_admin()) {
return ' ...';
}
}
add_filter('the_content_more_link', 'generic_read_more_link');
function generic_excerpt_read_more_link($more) {
if (!is_admin()) {
global $post;
return ' ...';
}
}
add_filter('excerpt_more', 'generic_excerpt_read_more_link');
add_action('widgets_init', 'generic_widgets_init');
To
function generic_read_more_link() {
if (!is_admin()) {
return ' Read more';
}
}
add_filter('the_content_more_link', 'generic_read_more_link');
function generic_excerpt_read_more_link($more) {
if (!is_admin()) {
global $post;
return ' Read more';
}
}
add_filter('excerpt_more', 'generic_excerpt_read_more_link');
add_action('widgets_init', 'generic_widgets_init');
However, I have no idea how I need to override it. If I change the words only I will get a blank page only.
You have two options:
Add your own functions with higher priority
function namespace_read_more_link() {
if (!is_admin()) {
return ' Read More';
}
}
add_filter('the_content_more_link', 'namespace_read_more_link', 15);
Remove the parent theme functions.
/* Remove the parent filter */
function child_remove_parent_read_more() {
remove_filter('the_content_more_link', 'generic_read_more_link_child');
}
add_action( 'wp_loaded', 'child_remove_parent_read_more' );
/* Add our own filter */
function namespace_read_more_link() {
if (!is_admin()) {
return ' Read More';
}
}
add_filter('the_content_more_link', 'namespace_read_more_link');
For more information, read the article that Dedering posted on Pluggable Functions in Wordpress.
You can't override it because it's not a pluggable function. Pluggable Functions
You cant override those, looks like the parent-theme wasn't made so you can.
What you will have to do (and its not ideal) its change the names:
function generic_read_more_link_child() {
if (!is_admin()) {
return ' Read more';
}
}
add_filter('the_content_more_link', 'generic_read_more_link_child');
function generic_excerpt_read_more_link_child($more) {
if (!is_admin()) {
global $post;
return ' Read more';
}
}
add_filter('excerpt_more', 'generic_excerpt_read_more_link_child');
add_action('widgets_init', 'generic_widgets_init');
so your theme-child functions will also be execute after the parent ones, of course this doesn't stop the parent ones.

Resources