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

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.

Related

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.

Symfony and PhpUnit memory leak

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 :)

Laravel 4 Model Events don't work with PHPUnit

I build a model side validation in Laravel 4 with the creating Model Event :
class User extends Eloquent {
public function isValid()
{
return Validator::make($this->toArray(), array('name' => 'required'))->passes();
}
public static function boot()
{
parent::boot();
static::creating(function($user)
{
echo "Hello";
if (!$user->isValid()) return false;
});
}
}
It works well but I have issues with PHPUnit. The two following tests are exactly the same but juste the first one pass :
class UserTest extends TestCase {
public function testSaveUserWithoutName()
{
$count = User::all()->count();
$user = new User;
$saving = $user->save();
assertFalse($saving); // pass
assertEquals($count, User::all()->count()); // pass
}
public function testSaveUserWithoutNameBis()
{
$count = User::all()->count();
$user = new User;
$saving = $user->save();
assertFalse($saving); // fail
assertEquals($count, User::all()->count()); // fail, the user is created
}
}
If I try to create a user twice in the same test, it works, but it's like if the binding event is present only in the first test of my test class. The echo "Hello"; is printed only one time, during the first test execution.
I simplify the case for my question but you can see the problem : I can't test several validation rules in different unit tests. I try almost everything since hours but I'm near to jump out the windows now ! Any idea ?
The issue is well documented in Github. See comments above that explains it further.
I've modified one of the 'solutions' in Github to automatically reset all model events during the tests. Add the following to your TestCase.php file.
app/tests/TestCase.php
public function setUp()
{
parent::setUp();
$this->resetEvents();
}
private function resetEvents()
{
// Get all models in the Model directory
$pathToModels = '/app/models'; // <- Change this to your model directory
$files = File::files($pathToModels);
// Remove the directory name and the .php from the filename
$files = str_replace($pathToModels.'/', '', $files);
$files = str_replace('.php', '', $files);
// Remove "BaseModel" as we dont want to boot that moodel
if(($key = array_search('BaseModel', $files)) !== false) {
unset($files[$key]);
}
// Reset each model event listeners.
foreach ($files as $model) {
// Flush any existing listeners.
call_user_func(array($model, 'flushEventListeners'));
// Reregister them.
call_user_func(array($model, 'boot'));
}
}
I have my models in subdirectories so I edited #TheShiftExchange code a bit
//Get all models in the Model directory
$pathToModels = '/path/to/app/models';
$files = File::allFiles($pathToModels);
foreach ($files as $file) {
$fileName = $file->getFileName();
if (!ends_with($fileName, 'Search.php') && !starts_with($fileName, 'Base')) {
$model = str_replace('.php', '', $fileName);
// Flush any existing listeners.
call_user_func(array($model, 'flushEventListeners'));
// Re-register them.
call_user_func(array($model, 'boot'));
}
}

Understanding OOP in Actionscript

A.as :
public class A {
public function getFunction():Function {
return function():void {
if(this is C) {
trace("C");
} else {
trace("not C");
}
}
}
public function func1():void {
var internalFunc:Function = getFunction();
internalFunc();
}
}
B.as :
public class B extends A implements C {
}
In some other class :
var b:B = new B();
B.func1();
Output is :
"Not C"
I was expecting the trace output to be
"C"
Can someone explain why?
An anonymous function, if called directly, is scoped to the global object. If you trace this inside it, you will see [object global] instead of [object B], as you would, if this refered to b.
A common workaround is using a closure:
var self:A = this;
return function():void {
if(self is C) {
trace("C");
} else {
trace("not C");
}
}
Please note however, the instance-members of a class defining an anonymous function are available from within. This works, because they are resolved at compile time.
edit in response to Amarghosh's question:
Yes, this points to the global object, but that doesn't mean, you cannot access the instance members of the declaring class. This little piece of code should explain the details:
package {
import flash.display.Sprite;
public class Test extends Sprite {
private var foo:String = "foo";
public function Test() {
var anonymous:Function = function ():void {
trace(foo);//foo
trace(this.foo);//undefined
};
anonymous();
}
}
}
greetz
back2dos
A few things with the code that I assume are just typos?
The getFunction() method doesn't return anything and will thus cause a compiler error.
Your call code calls func1() as a static method, not as a method on an instance of the B. This will also cause a compiler error. I believe these are typos.
In my tests, using your modified code. The output is C. There must be something else going on with your code. Here are my mods to A:
public function getFunction():Function {
if(this is C) {
trace("C");
} else {
trace("not C");
}
return getFunction;
}
Here is my mod to the runnable code, which I put in creationComplete of an empty MXML Application file:
var b:B = new B();
b.func1();
I assume your "real world" code is more extensive than the sample and there must be something else going on.

Resources