I try to make a suite of tests with phpunit with dependence between several classes. I have 3 classes, A, B and C, with tests in each classes. A has 5 tests, B 3 tests et C 3 tests.
B has dependant tests on A, C has dependant tests on A and the A final tests depends on B and C tests.
class A extends TestCase {
public function test1(){}
// #depends test1
public function test2(){}
// #depends test2
public function test3(){}
// #depends test3
public function test4(){}
// #depends test3
// #depends B::test3
// #depends C::test3
public function test5(){}
}
class B extends TestCase {
// #depends A::test1
public function test1(){}
// #depends B::test1
public function test2(){}
// #depends B::test2
// #depends A::test4
public function test3(){}
}
class C extends TestCase {
// #depends A::test1
public function test1(){}
// #depends C::test1
public function test2(){}
// #depends C::test2
// #depends A::test4
public function test3(){}
}
My problem in this case is that A::test5, B::test3 and C::test3 are skipped.
what you have is a very poor design for your tests.
You should be able to run all your tests independently of each other.
If you need certain data to be setup beforehand, then do it in a setUp() method, or in the test method itself.
As has already been pointed out, if you have external dependencies, mock them.
If you have a set of tests that all require the same, or similar data, then its perfectly acceptable to put that setup code in a base class, and then extend that with your tests. Something like this.
class AppTestCase extends TestCase
{
public function setUp()
{
// this will be run before every test class that extends this class. So make your test user/product here.
// you can invoke all your mocking in here to if thats easier,
// just make sure the resulting mock objects are all in visible
// properties to be accessed elsewhere
}
public function tearDown()
{
// if youre functional testing, remove test data in here. This will fire after each test has finished in any class that extends this one.
}
}
class A extends AppTestCase
{
public function setUp()
{
parent::setUp();
// do other, class specific setup stuff here.
}
public function test1()
{
// your test data will be setup for you by the time you get here.
// if you only have 1 test and it needs adapted base data, do it here,
// if you have lots of tests in here, override and extend the `parent::setUp()` method.
}
}
then repeat that pattern for all your tests.
Related
I have a Symfony WebTestCase-extending PHP Test class and a DRY-trait. The test functions in my class #depend on the test functions in my trait, however I can't manage to execute the trait tests before the class tests. Is that possible?
trait TestTrait
{
/**
* #beforeClass
*/
public function testBeforeAnythingElseHappens()
{
/*...*/
}
/* more functions */
}
Test Class
class Test extends WebTestCase
{
use TestTrait;
/**
* #depends testBeforeAnythingElseHappens
*/
function testClassSpecificStuff()
{
/* ... */
}
}
First, see PHPUnit Manual - Appendix B. Annotations:
#beforeClass
The #beforeClass annotation can be used to specify static methods that should be called before any test methods in a test class are run to set up shared fixtures.
So, you should not use #beforeClass here - it is intended to allow setting up fixtures. In addition, the methods annotated as such should be static.
Second, see PHPUnit Manual - Appendix B. Annotations:
#depends
PHPUnit supports the declaration of explicit dependencies between test methods. Such dependencies do not define the order in which the test methods are to be executed but they allow the returning of an instance of the test fixture by a producer and passing it to the dependent consumers.
So yes, you could use the #depends annotation to declare dependencies between tests. Just remove the #beforeClass annotation:
trait TestTrait
{
public function testBeforeAnythingElseHappens()
{
}
}
class Test extends WebTestCase
{
use TestTrait;
/**
* #depends testBeforeAnythingElseHappens
*/
public function testClassSpecificStuff()
{
}
}
Third, a few words of advice (from my own experience):
Do not require tests to be run in a certain order.
If you arrange something in one test and need the same thing in another, just do it multiple times, do not worry too much about repeating yourself.
For reference, see:
http://blog.ploeh.dk/2011/05/24/DesignSmellTemporalCoupling/
What does “DAMP not DRY” mean when talking about unit tests?
I like to ask you about your practice of writing unit test, how to mock object and don't repeat the code?
I am using Symfony2 framework and for example I have many bundles with custom validators. When me and the rest of my team writing unit test we repeat the code of mocking Constraint, ExecutionContext, ConstraintViolationBuilderInterface. I know that we can create trait or abstract class or something else where we can store code responsible for mocking but before I will start doing this I like to know your best practices.
My first idea was to create a class/trait which will store for example mock of all repositories. Example:
class MockRepositoryHelper extends \PHPUnit_Framework_TestCase
{
public function getUserRepositoryMock()
{
return $this->prophesize(UserRepository::class);
}
// next repositories getters
}
and then use this code in real test case:
class EmailValidator extends \PHPUnit_Framework_TestCase
{
private $mockRepositoryHelper;
public function setUp()
{
parent::setUp();
$this->mockRepositoryHelper = new MockRepositoryHelper();
}
/**
* #test
*/
public function it_should_find_user()
{
$userRepository = $this->mockRepositoryHelper->getUserReposioryMock();
$userRepository->findUser(Argument::type('string'))->willReturn(null);
// rest of the test
}
}
Of course this is only pseudo code what I imagined, my first thought. What are yours ideas?
Basically I am asking how to write unit test faster and don't repeat the code?
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.)
Here's a test PHPUnit test I wrote:
<?php
class MyTest extends PHPUnit_Framework_TestCase
{
public function __construct()
{
echo "starting tests\r\n";
parent::__construct();
}
public function provider()
{
return array(array('test'));
}
/**
* #dataProvider provider
*/
public function testProvider($var)
{
$this->assertEquals($var, $var);
//exit($var);
}
}
When I run it I get the following:
There was 1 error:
1) MyTest::testProvider
Missing argument 1 for MyTest::testProvider()
/home/myname/test.php:19
FAILURES!
Tests: 1, Assertions: 0, Errors: 1.
My question is... why? And what can I do about it?
In the actual unit tests I'm writing (the above is just a test demonstrating the problem) I'm testing a class with several different backend engines. I have an abstract class with a bunch of test cases and a protected class variable named $engine. I then have a bunch of classes that extend this abstract class and set $engine in the constructor. In each of the test methods in the abstract method $obj->setEngine($this->engine) is then called to test the specific engine in question. But this approach seems to break unit tests with providers and in lieu of that I'm not sure what I should be doing.
Any ideas?
Instead of implementing a constructor, you should use the static method setUpBeforeClass to create the $engine. The engine must be stored in a static property.
https://phpunit.de/manual/current/en/fixtures.html#fixtures.sharing-fixture
So, I've got a little problem with my Unittests. I wrote some basisclasses for different Testcases and I want to uses some prepared test-methods.
i.e.
class ModelTestCase extends PHPUnit_Framework_TestCase {
public function testCreateInstance() { ... }
}
class UserModelTest extends ModelTestCase {
/**
* (at)depends testCreateInstance
*/
public funcion testWhatever($model) { ...}
}
Is there any trick to use it as I want or must I really write every test in every class?
It all depends on what you really want to do, your code sample is way too vague to tell that.
One option for you is to create your own setup() method in ModelTestCase (dont forget to call parent::setUp()) and do some initialization in there.
If you want to test only the derived model tests, but not the base class itself, you can declare it as abstract:
abstract class ModelTestCase extends PHPUnit_Framework_TestCase {
public function testCreateInstance() { ... }
}
This worked for me.