I'm working on a PHP project and use PHPUnit and Doctrine 2. I use the latest version at all. I wrote a lot of tests to test all the classes, functions and behavior. The tests are always running. Everything worked fine. Since I use Doctrine, I have applied the best-practice tips and initializes the ArrayCollection in the constructor.
public function __construct($username, $eMail, $password1, $password2) {
$this->quiz = new ArrayCollection();
$this->sessions = new ArrayCollection();
$this->setUsername($username);
$this->setEMail($eMail);
$this->setPassword('', $password1, $password2);
}
The include of the ArrayCollection is:
use Doctrine\Common\Collections\ArrayCollection;
After this point, the PHPUnit tests are no longer running.
When I comment the line with the initialization all test run again. The members quiz and sessions are private. The application generally works.
I'm new with Doctrine 2 and PHPUnit. I've tried many things until now like different includes in the testcase etc. But nothing has helped.
Maybe I forgot something in the testcase. Between the step initialization of the ArrayCollection and without initialization I have changed nothing in the testcase.
The testcase looks like this:
namespace Model;
require_once dirname(__FILE__) . '/../../Model/User.php';
/**
* Test class for User.
* Generated by PHPUnit on 2012-04-03 at 14:48:39.
*/
class UserTest extends \PHPUnit_Framework_TestCase {
/**
* #var User
*/
protected $user;
// constructor of the test suite
function UserTest($name) {
$this->PHPUnit_TestCase($name);
}
/**
* Sets up the fixture, for example, opens a network connection.
* This method is called before a test is executed.
*/
protected function setUp() {
$username = 'musteruser';
$eMail = 'must#muster.ch';
$pw = 'muster.muster';
$this->user = new User($username, $eMail, $pw, $pw);
}
/**
* Tears down the fixture, for example, closes a network connection.
* This method is called after a test is executed.
*/
protected function tearDown() {
unset($this->user);
}
Right now I really have no idea what could be the problem. Maybe someone has already experienced the same thing or has any idea what could be the problem.
Thanks for any help.
You may need to ensure that the Doctrine\Common folder is on the include path for your test cases when you call PHPUnit.
Are you customizing any class loaders for your application, since you need to do the same for your tests.
I have found a solution for the problem. I created a file with the name bootstrap.php with the following content:
// Import the ClassLoader
use Doctrine\Common\ClassLoader;
// Autoloader for Doctrine
require '/../../php/PEAR/Doctrine/Common/ClassLoader.php';
// Autoloading for Doctrine
$doctrineClassLoader = new ClassLoader('Doctrine', realpath(__DIR__ . '/../../php/PEAR'));
$doctrineClassLoader->register();
The file is placed in the home directory of Test Files, the part for Unit Testing in a NetBeans project. The important thing is, that is nothing to edit in the testcases.
Related
tl;dr: Will this potentially keep my tests from working properly?
I'm trying to write functional tests for my Symfony project, and working from examples in The Symfony Book. So far, each method of the test class starts out with the same line of code:
namespace Tests\AppBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
class SomeControllerTest extends WebTestCase
{
public function testSomethingOnRouteX()
{
$client = static::createClient();
// set up and assert
}
public function testSomethingElseOnRouteX()
{
$client = static::createClient();
// different set up and assert
}
}
I would like to remove this redundant code, but I am not sure if I should do this.
I added a constructor where I created the client.
public function __construct()
{
parent::__construct();
$this->client = static::createClient();
}
then in the various test methods I can just use $this->client without needing to create it repeatedly. This seems to work so far (I don't have many tests yet.) But I'm new enough to this framework, and to this type of testing in general that I'm not sure if it will cause problems down the road.
The recommended way to do it is to either use the setUp() method, or the #before hook. Both are called before each test method, so you're safe as the state won't be shared between test cases. Cleanup is also done for you automatically after each test case is run (implemented in the WebTestCase class).
namespace Tests\AppBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
use Symfony\Bundle\FrameworkBundle\Client;
class SomeControllerTest extends WebTestCase
{
/**
* #var Client
*/
private $client;
protected setUp()
{
$this->client = self::createClient();
}
public function testSomethingOnRouteX()
{
// set up and assert
$this->client->request('GET', '/something');
}
public function testSomethingElseOnRouteX()
{
// different set up and assert
$this->client->request('GET', '/something-else');
}
}
Alternatively to setUp() you can use the #before hook:
namespace Tests\AppBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
use Symfony\Bundle\FrameworkBundle\Client;
class SomeControllerTest extends WebTestCase
{
/**
* #var Client
*/
private $client;
/**
* #before
*/
protected function setUp()
{
$this->client = self::createClient();
}
// ...
}
If you try it, you should probably use the setUp-method instead. Reusing a client might introduce side effects, which is something you try to avoid. If your tests start to randomly fail, you probably want to try to go back to creating a new client per test. I wouldn't recommend it, but more from a gut feeling than actual bad experience. It should work fine most of the time, but when you suddenly reuse a client with for example a differently set header and it doesn't work you will have a headache.
I don't think there will be a huge performance gain as ui-tests are slow anyway, so trying to have as few test cases is probably a better way to go (look for test pyramid, if you don't know what I mean) if that's your aim.
It may work or may not work, depending on what you're testing.
A new client is like a fresh browser installation. No cookies are set, no history, no actual page, and so on.
If you're testing auth for example, it would be really bad if testCanNotAccessInternalResourceIfNotLoggedIn would use the client which is still logged in because testLogInWithCorrectCredentialsWorks ran before it and therefore fails. Sure, you can make sure you logout the user before accessing the resource but just creating a clean new browser instance is the easiest and least error-prone way to do it.
I've been reading this manual, but I'm not understanding why the $stack loose the values after each test function.
Here's my code:
require_once BASE . 'Transaction.php';
class TransactionTest extends PHPUnit_Framework_TestCase
{
protected $stack;
protected function setUp()
{
Database::getInstance()->connect();
$this->stack = new Transaction(123456789);
}
public function testInsert()
{
$data['name'] = 'Omega';
$this->stack->set($data);
$this->assertTrue($this->stack->save());
}
public function testUpdate()
{
$object = PHPUnitReflectionClass::getInstance($this->stack);
$this->assertEquals(array('name' , 'Omega'), $object->getProperty('name'));
}
}
At the "testUpdate" function, I don't have the name.
If I just copy all the PHPUnit example, all tests will run perfectly, but I'm not able to see the values using var_dump at the next function. And this is another thing that I don't get it.
The problems are:
the setup method is called before each test method invocation;
your test are depends each other.
For the first problem you can use the setUpBeforeClass method. From the doc:
The setUp() and tearDown() template methods are run once for each test
method (and on fresh instances) of the test case class.
In addition, the setUpBeforeClass() and tearDownAfterClass() template
methods are called before the first test of the test case class is run
and after the last test of the test case class is run, respectively.
For the second problem, is a bad practice to have tests that depends each otherbut PHPUnit supports the declaration of explicit dependencies between test methods, so you can use the #depends annotation to express dependencies: if a test fail the other is not executed.
So your test class can be, as example:
require_once BASE . 'Transaction.php';
class TransactionTest extends PHPUnit_Framework_TestCase
{
protected static $stack;
public static function setUpBeforeClass()
{
Database::getInstance()->connect();
$this->stack = new Transaction(123456789);
}
public function testInsert()
{
$data['name'] = 'Omega';
$this->stack->set($data);
$this->assertTrue($this->stack->save());
}
/**
* #depends testInsert
*/
public function testUpdate()
{
$object = PHPUnitReflectionClass::getInstance($this->stack);
$this->assertEquals(array('name' , 'Omega'), $object->getProperty('name'));
}
}
Hope this help
Unit tests should not depend on other tests, it's considered bad practice. The point of unit tests is that they run in a controlled and isolated environment. The setUp() and tearDown() methods are called respectively before and after each test method. And thus your $stack property is overwritten before each test. This is also pointed out in the document you linked to (just below example 4.1):
The setUp() and tearDown() template methods are run once for each test method (and on fresh instances) of the test case class.
(You're also making the assumption that the methods in your test class are run in the same order that they are written, but that isn't necessarily the case. Most of the time they do run in the same order, but you can't depend on it.)
I have a unit tested application which we have updated from symfony 2.3 to 2.6. We followed all upgrading docs and had to change only some minor stuff.
Everything is working perfectly, except for the PHPUnit tests.
We have 2 seperate runs, one for only testing the entity classes, which is fired on a pre-commit hook. and a second one which runs the full suite, with database setups and the whole nine yards.
Now since the upgrade to 2.6, the PHPUnit_Framework_Error thrown in the unit tests have been replaced by Symfony's Symfony\Component\Debug\Exception\ContextErrorException, this failing all tests like this:
/**
* #dataProvider objectTestDataProvider
* #expectedException \PHPUnit_Framework_Error
*/
public function testCanNotSetClientToArbitraryValue($value)
Now I do not want to change this into the new Exception since running the entity-only test suite does not depend on symfony components, thus symfony is not loaded, thus the errors are the regular PHPUnit_Framework_Error so changing it makes these tests fail.
In other words, when I run one test class it works, once a symfony dependent test is run, it fails:
# runs perfectly
phpunit -c app/phpunit.xml --debug src/My/Bundle/Tests/Entity
# fails when reaching the tests that ran perfectly in previous command
phpunit -c app/phpunit.xml --debug
This new ErrorHandler seems undocumented, I couldnt find much about it in google except for the pull request and this small article
I've tried:
setting the SYMFONY_DEBUG=0 environment variable, but this doesnt seem to make any difference.
adding the debug.error_handler.throw_at: 0 parameter to my test_config.yml
edit:
On request by #cerad I've tried to isolate the tests to try and reproduce the code with as little as possible, Ive managed to reproduce with 4 tests:
class MyControllerTest extends WebTestCase
{
public function testRoutesLoaded_1()
{
$client = self::createClient();
/** #var Router $router */
$router = $client->getKernel()->getContainer()->get('router');
$this->assertEquals('/menu', $router->generate('front_menu'));
}
/**
* #expectedException \PHPUnit_Framework_Error
*/
public function testCreateOrder_1()
{
new Order(); // required parameter missing
}
public function testRoutesLoaded_2()
{
$client = $this->createNewFrontClient();
/** #var Router $router */
$router = $client->getKernel()->getContainer()->get('router');
$this->assertEquals('/menu', $router->generate('front_menu'));
}
/**
* #expectedException \PHPUnit_Framework_Error
*/
public function testCreateOrder_2()
{
new Order(); // required parameter missing
}
}
As you can see, I just run the same exact test 2 times, but still the last one results in an error:
MyControllerTest::testCreateOrder_2
Failed asserting that exception of type "Symfony\Component\Debug\Exception\ContextErrorException" matches expected exception "\PHPUnit_Framework_Error"
Since I did not get any replies here, I posted an issue on Symfony's github and they confirmed this was incorrect behavior.
The issue was resolved and is merged in 2.6-dev.
When mocking an interface in PHPUnit, PhpStorm complains when it's used as parameter for a type-hinted function.
Example
interface InterfaceA{
}
class ClassA{
public function foo(InterfaceA $foo){}
}
class PhpStormTest extends PHPUnit_Framework_TestCase
{
public function testFoo(){
$mock = $this->getMock("InterfaceA");
$a = new ClassA();
$a->foo($mock);
}
}
On $a->foo($mock); PhpStorm underlines $mock with the warning Expected InterfaceA, got PHPUnit_Framework_MockObject_MockObject
Image
I guess it's happening because PHPUnit creates the mock a runtime and PhpStorm cannot know that it's actually implementing the interface.
I found a workaround to this problem in the Jetbrain blog at PhpStorm Type Inference and Mocking Frameworks. The important part:
By default, PhpStorm is capable of figuring out the available methods
on the mock object. However, it only displays those for PHPUnit’s
PHPUnit_Framework_MockObject_MockObject class. Fortunately, we can
solve this by instructing PhpStorm to infer type information from
other classes as well, by using a simple docblock comment.
So to make the warning disappear, we need to add /** #var InterfaceA */ /** #var InterfaceA|PHPUnit_Framework_MockObject_MockObject */ (cudos to Supericy) to let PhpStorm know our mock actually implements InterfaceA:
interface InterfaceA{
}
class ClassA{
public function foo(InterfaceA $foo){}
}
class PhpStormTest extends PHPUnit_Framework_TestCase
{
public function testFoo(){
/** #var InterfaceA|PHPUnit_Framework_MockObject_MockObject */
$mock = $this->getMock("InterfaceA");
$a = new ClassA();
$a->foo($mock);
}
}
This bugged me for some time, hope it helps someone :)
Edit
Since PHPUnit_Framework_MockObject_MockObject is really ugly to type, you can abbreviate it via MOOMOO and let PHPStorms auto-complete do the rest:
Another plugin I have used for this is the Dynamic Return Type Plugin, it lets you configure return types of methods in a very dynamic way (the example is to have better type information from Mocks).
Another, less verbose but possibly riskier, approach can be to wrap the call to getMock() with your own function and mark that with #return mixed:
/**
*
* #return mixed
*/
public function myGetMock($str)
{
return $this->getMock($str);
}
Calling this method instead of $this->getMock() will make the warning disappear.
I am trying to build a secure of set of tests with Symfony2, Doctrine and MongoDB.
What I need to do is to load a lot of fixtures when a test begin, and unload them once it ends. I thought of doing it with a transaction, but... I couldn't find documentation on how to do it with Doctrine and Mongo!
I found good documentation in the Doctrine docs regarding how to do transactions with the ORM, but not regarding the ODM.
So I took a look at the source code of the Connection.php class used by Doctrine-Mongo too and I haven't found the beginTransaction, commitand rollback methods that the dbal version uses.
I was clueless, then I asked myself "Is it even possible to rollback in MongoDB?", and the answer if found in the MongoDB FAQ was:
MongoDB does not use traditional locking or complex transactions with rollback
:( So I guess that's why there is no beginTransaction or whatsoever in the ODM...
But my problem remains: how can I implement a sort of rollback for my tests?
The only idea I got right now is to manually get all the ids of the Document I load and then remove them in the tearDown(). But, well... it kinda sucks, doesn't it?
Other ideas??
EDIT:
After my first comment to this question, regarding the fact that I want to have the same DB in test and development, I thought: why don't use a separate test database, where the development database gets copied when the tests start, and that can be light-heartedly dropped?
Could it be a better idea? It actually looks easier and more secure to me. What do you guys think?
Thanks :)
I am not using two separate DBs for development and testing
That's the first thing to address - because without a testing db, running tests will affect your development db and vice versa which is a terrible idea. You should be able to run tests in your production environment with absolute confidence that nothing you do in a test will affect your deployed site.
Setup a test connection
So, modify your parameters.yml to have something like this:
database.host: localhost
database.port: 27017
database.db: myappname
database.test.host: localhost
database.test.port: 27017
database.test.db: myappname-test
In addition, in your app/config/config_test.yml file override the default connnection so that anything you trigger as part of a test which requests the default document manager will receive a manager pointing at your test db:
doctrine_mongodb:
document_managers:
default:
database: %database.test.db%
Prepare for tests with fixtures
Then, what you want to do effectively is:
truncate relevant collections
load fixtures
on your test db before each test.
Here's an example abstract test class:
<?php
use Doctrine\Common\DataFixtures\Executor\MongoDBExecutor as Executor,
Doctrine\Common\DataFixtures\Purger\MongoDBPurger as Purger,
Doctrine\Common\DataFixtures\Loader,
Doctrine\Common\DataFixtures\ReferenceRepository,
Symfony\Bundle\FrameworkBundle\Test\WebTestCase,
Symfony\Bundle\FrameworkBundle\Console\Application;
abstract class AbstractTest extends WebTestCase
{
/**
* Array of fixtures to load.
*/
protected $fixtures = array();
/**
* Setup test environment
*/
public function setUp()
{
$kernel = static::createKernel(array('environment' => 'test', 'debug' => false));
$kernel->boot();
$this->container = $kernel->getContainer();
$this->dm = $this->container->get('doctrine.odm.mongodb.document_manager');
if ($this->fixtures) {
$this->loadFixtures($this->fixtures, false);
}
}
/**
* Load fixtures
*
* #param array $fixtures names of _fixtures to load
* #param boolean $append append data, or replace?
*/
protected function loadFixtures($fixtures = array(), $append = true)
{
$defaultFixtures = false;
$loader = new Loader();
$refRepo = new ReferenceRepository($this->dm);
foreach ((array) $fixtures as $name) {
$fixture = new $name();
$fixture->setReferenceRepository($refRepo);
$loader->addFixture($fixture);
}
$purger = new Purger();
$executor = new Executor($this->dm, $purger);
$executor->execute($loader->getFixtures(), $append);
}
}
Use fixtures in your tests
With the previous abstract test class, you can then write tests which use your fixture data - or not - as appropriate. Below is a trivial example.
<?php
use Your\AbstractTest,
Your\Document\Foo;
class RandomTest extends AbstractTest
{
/**
* fixtures to load before each test
*/
protected $fixtures = array(
'APP\FooBundle\DataFixtures\MongoDB\TestFoos',
'APP\FooBundle\DataFixtures\MongoDB\TestBars'
);
...
/**
* Check it gets an ID (insert succeeded)
*
*/
public function testCreateDefaults()
{
$foo = new Foo();
$this->dm->persist($foo);
$this->dm->flush();
$this->assertNotNull($foo->getId());
$this->assertSame('default value', $foo->getSomeProperty());
// etc.
}
/**
* Check result of something with a given input
*
*/
public function testSomething()
{
$foo = $this->dm->getRepository(APPFooBundle:Foo)->findByName('Some fixture object');
$foo->doSomething();
$this->assertSame('modified value', $foo->getSomeProperty());
// etc.
}
Before each test, the fixtures you've defined will be loaded (truncating the collections they affect), giving a consistent db state on which to base your tests.
Just drop your MongoDB database before each test and then load the fixtures you need. This way each test will be fully isolated.