I am working on re-configuring our php unit test setup and ran into a need to run tests that belong to a specific group by only if they also belong to another group. For example, I may have something like this:
/**
* ...
* #group Alpha
* #group area1
*/
class TestAlpha extends PHPUnit_Framework_TestCase
{
public function testTest1() {
...
}
public function testTest1() {
...
}
}
/**
* ...
* #group numeric
* #group area1
*/
class TestNumeric extends PHPUnit_Framework_TestCase
{
public function testTestA() {
...
}
public function testTestB() {
...
}
}
If I only want to run tests from area1 group, I would use
phpunit --group area1
However I also need to be able to run tests from area1 group but only if they also belong to numeric group.
If I run phpunit --group area1,numeric, the tests will be included if they are in one or the other group. How can I run phpunit to only include tests if they are in one and the other group? Sort of like --filter parameter but on a group level.
Just to note, I'm dealing with an existing suite of several hundred test classes and massively restructuring the tests (e.g. in separate suites) isn't something I can afford at the moment.
phpunit --list-group -c selenium.xml selenium/
by using this list all groups
phpunit --exclude-group alpha --group numeric -c selenium.xml selenium/
exclude group which you don't want to use like alpha
Related
I want to reset my test database after each test but somehow can't find a way to do it. Can delete the data added in each test but I am pretty sure this is not the correct approach. What I have as test is simply this:
<?php
declare(strict_types=1);
namespace Tests\Unit\Entity;
use App\Repository\UserRepository;
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
use Tests\Shared\Factory\UserFactory;
final class UserTest extends KernelTestCase
{
public function testGettersReturnCorrectData(): void
{
self::bootKernel();
/** #var UserRepository $repo */
$repo = self::getContainer()->get(UserRepository::class);
$user = UserFactory::createUser();
$repo->add($user, true);
$this->assertSame($user->getEmail(), UserFactory::EMAIL);
$this->assertSame($user->getPassword(), UserFactory::PASSWORD);
$this->assertSame($user->getReferralCode(), UserFactory::REFERRAL_CODE);
}
}
The newly created user stays in the db. I am using MySQL test db because my production db will be MySQL and don't want to reach some corner cases because of the different dbs.
This is my env.test if needed.
# define your env variables for the test env here
KERNEL_CLASS='App\Kernel'
APP_SECRET='$ecretf0rt3st'
SYMFONY_DEPRECATIONS_HELPER=999999
PANTHER_APP_ENV=panther
PANTHER_ERROR_SCREENSHOT_DIR=./var/error-screenshots
DATABASE_URL="mysql://root:toma123#127.0.0.1:3306/api?serverVersion=5.7&charset=utf8mb4"
by the love of god, follow #craigh 's advice and look into foundry
https://symfony.com/bundles/ZenstruckFoundryBundle/current/index.html#database-reset
they do exactly that, and actually provide good stuff so you can build your test database inside each test case. Symfony's fixtures solution, in my subjective opinion, is worse than foundry.
I'm using #testdox annotation in PHPUnit 8 to set the description for my tests.
This works fine, but I'd like to be able to set the description dynamically. A method like this would be nice:
$this->setTestDoxDescription("My super test routine for date: ".$mydate->format('Y-m-d');
I have tests that check the results of various date-related functions. Many of the tests are relative to today's date, so the input date values are not fixed and are generated dynamically. I would like to be able to print the date values in the description.
I just discovered the setName() method in TestCase and it seems to do mostly what I want:
$this->setName("My super test routine for date: ".$mydate->format('Y-m-d');
However, there is some kind of parsing and it is splitting my dates on - chars and adding extra spaces. For example, 2020-04-04 is changed to 2020- 04- 04. But if I use #testdox 2020-04-04 it does not split things. It is only a problem when I use setName(). Not a big deal, but kind of annoying.
I've solved my problem for now, but maybe someone can recommend a better way.
You can put variable names into the #testdox string, the variables that are being returned from the #dataprovider (given as the method parameters).
An example from phpunit's own tests...
/**
* #testdox Valid regex $pattern on $subject returns $return
* #dataProvider validRegexpProvider
*
* ....
*/
public function testValidRegex($pattern, $subject, $return): void
I've just added it to my own tests and one dataprovider/testdox output example is:
#testdox displayNumber formats $input as '$expectedLong' & '$expectedShort'
public function testNumber($input, $expectedLong, $expectedShort): void {}
✔ displayNumber formats 1781234 as '1,781,234' & '1.8M'
I have 2 entities, Client and Campaign.
Client Entity
/**
* #ORM\OneToMany(targetEntity="Campaign", mappedBy="client")
*/
protected $campaign;
+++++++++++++++++++++++++++++
Campaign Entity
/**
* #var integer
*
* #ORM\Column(name="numberOfBid", type="integer", nullable=true)
*/
protected $numberOfBid;
/**
* #ORM\ManyToOne(targetEntity="Clients", inversedBy="campaign")
* #ORM\JoinColumn(name="client_id", referencedColumnName="client_id")
*/
protected $client;
/* Let's say
Client A has Campaign A, numberOfBid = 1
Client A has Campaign B, numberOfBid = 5
Client A has Campaign C, numberOfBid = 3
Client A has Campaign D, numberOfBid = 4
Total numberofBid = 13
*/
Problem: How do I get the sum of all numberOfBid and show it as 1 column in the Client Admin List Board? On the method configureListFields, I tried different ways like using sonata_type_model, doctrine_orm_callback, query but still didn't work.
Client ID | Campaign TotalBid
A | 13
Hoping for your feedback.
Thanks in advance.
First you should rename your
protected $campaign;
in
protected $campaigns;
cause it's a collection. One client has many campaigns.
To your problem: You could implement a method on your client entity something like this
class Client{
...
public function getTotalNumberOfBids() {
$i = 0;
foreach ($this->getCampaigns() as $campaign) {
$i += $campaign->getNumberOfBid();
}
return $i;
}
...
}
and add to your list view by
protected function configureListFields(ListMapper $list)
{
$list
...
->add('totalNumberOfBids');
}
The "magic getter" will automatic invoke the getTotalNumberOfBids method.
Note: Dependent on the number of objects holding by the campaigns collection, the summation of the numberOfBids could be slow due to the use of the foreach loop.
There are some conventions in symfony that can be found here http://symfony.com/doc/2.8/contributing/code/conventions.html ... so if you want to access a property from your entity and you dont get it explicit by calling it with an leading keyword like "get" or "is", symfony (or maybe a underlying framework) automatic tries to find a method starting with "get" or "has" and so on ... this is comfortable because you dont have to write the get, set, has and so on before your properties to call the getting and setting methods.
The tricky thing is, that sonata admin bundle doesn't give you an error in the list view if a property isn't found. For example totalnumberOfBids will left your column empty without any error, cause you dont match the camel-case for the part "number". So you should be aware of naming/calling your properties correct or you will end up in a long time of headache ...
I am introducing functional behat tests on a Symfony2/Doctrine2 application and am deciding how to handle database isolation and data fixtures.
Are there any pitfalls to setting up a separate test environment with its own completely separate mysql database that gets populated by a dump import prior to execution of the behat test suite, and then emptied after suite execution? I'm trying to avoid using data fixtures unless I really need so as to save the time of manually writing foreign key relations and what not.
Any guidance is appreciated.
As far as Symfony/Doctrine/Behat is concerned and if you want to be one of those who follows the best practises then:
You should isolate your environment dev, test, prod, stag ...
Setting up isolated environments as a symfony application base
up to Build folder structure header.
You should isolate your test database and use sqlite instead of
MySQL for performance purposes. Using multiple SQLite entity
managers for multiple bundles and databases in test environment,
you can use only one.
You should use fixtures to give yourself flexibility and get rid of
burden of manual processing. Do not try to avoid using them!
Creating doctrine data fixtures in symfony
So on ..... just check the posts in this site which I often
read up on myself.
Behat 3 composer entries and the behat.yml
We currently have a separate test database and use a combination of both fixtures and prepopulated database.
The prepopulated database contains the minimum information that needs to be present in almost all tests. We used to do this with fixtures but it was too slow, so now we populate the DB like so:
/**
* #BeforeScenario
*/
function initialiseStorage(BeforeScenarioScope $scope)
{
$con = $this->getService('database_connection');
$con->executeUpdate("SET foreign_key_checks = 0;");
$filePath = $this->getMinkParameter('files_path').'/test_db.sql';
$con->exec(file_get_contents($filePath));
$con->executeUpdate("SET foreign_key_checks = 1;");
}
And then, we load the specific fixtures for every test case like Alfonso described.
We use MYSQL for our tests as in our experience the bottleneck is not the DB but doctrine's metadata caching. If you set up metadata caching in redis the speed of the tests increase dramatically.
In order to respond to #madness-method and to complete the following answer:
The prepopulated database contains the minimum information that needs
to be present in almost all tests. We used to do this with fixtures
but it was too slow, so now we populate the DB like so:
/**
* #BeforeScenario
*/
function initialiseStorage(BeforeScenarioScope $scope)
{
$con = $this->getService('database_connection');
$con->executeUpdate("SET foreign_key_checks = 0;");
$filePath = $this->getMinkParameter('files_path').'/test_db.sql';
$con->exec(file_get_contents($filePath));
$con->executeUpdate("SET foreign_key_checks = 1;");
}
And then, we load the specific fixtures for every test case like
Alfonso described.
We use MYSQL for our tests as in our experience the bottleneck is not
the DB but doctrine's metadata caching. If you set up metadata caching
in redis the speed of the tests increase dramatically.
You should use instead:
/**
* #BeforeScenario
*/
function initialiseStorage(BeforeScenarioScope $scope)
{
$con = $this->em->getConnection();
$con->executeUpdate("SET foreign_key_checks = 0;");
$filePath = $this->getMinkParameter('files_path').'/test_db.sql';
$con->exec(file_get_contents($filePath));
$con->executeUpdate("SET foreign_key_checks = 1;");
}
having the following code in your Context file:
private $em;
public function __construct(EntityManagerInterface $em)
{
$this->em = $em;
}
Do not forget to add the following lines in your behat configuration file regarding your contexts in order to be able to use the entity manager in your constructor and then in your initialiseStorage method :
- AppBundle\Features\Context\FeatureContext:
em: '#doctrine.orm.default_entity_manager'
Basically to get the connection, we have replaced:
$this->getService('database_connection');
by:
$this->em->getConnection();
I recommend you to read something about factory girl pattern. The idea is create a
factory for every class that you have and use a instance of it in the test. I use https://github.com/carlescliment/handy-tests-bundle
Other options will be create your own steps to create a instance or the class something like this:
/**
* #Given /^there are products:$/
*/
public function thereAreRoutes(TableNode $table)
{
$em = $this->getEntityManager();
foreach ($table->getHash() as $hash) {
$entity = new Product();
$entity->setName($hash['name']);
$entity->setDescription(isset($hash['description']) ? $hash['description'] : $hash['description']);
$em->persist($entity);
}
$em->flush();
}
And you can use it like:
Given there are products:
| name | description |
| Shoes | It is blue |
in this tutorial is proposed this file system:
XXXBundle
|---Features
| |----FeaturesContext.php
|---ProductCategoryRelation.feature
where FeaturesContext.php is the file that stores the functions
//FeaturesContext.php
/**
* Feature context.
*/
class FeatureContext extends BehatContext
{
/**
* #Given /I have a category "([^"]*)"/
*/
public function iHaveACategory($name)
{
$category = new \Acme\DemoBundle\Entity\Category();
$category->setName($name);
...
And inside ProductCategoryRelation.feature is proposed to write the features and the scenarios:
Feature: Product Category Relationship
In order to setup a valid catalog
As a developer
I need a working relationship
This being the feature, we now need the scenarios to be defined.
Scenario: A category contains a product
Given I have a category "Underwear"
...
But if my app is growing up, how should refactor for example FeaturesContext.php?
You might use subcontexts to split step definitions into multiple context classes: http://docs.behat.org/guides/4.context.html#using-subcontexts