In my test cases, I have extend my test case class to another base class, where I have used setUp to set the global variables. I have extended this base class to child class where I have written test cases. Now, I have many child test classes which extends this base class. That's why, rather than using setUp in each child class, I have used only in base class.
This is my setup:
Base Class
use PHPUnit\Framework\TestCase;
class BaseClass extends TestCase
{
public static function setUpBeforeClass(){
//global vars setup
}
public static function tearDownAfterClass(){
//global vars teardown
}
}
Child Class
class ChildClass extends BaseClass
{
public static function setUpBeforeClass(){
//setup some other stuff related to only this child class
parent::setUpBeforeClass();
}
public static function tearDownAfterClass(){
//teardown some other stuff related to only this child class
parent::tearDownAfterClass();
}
}
Now, I want to use PHPUnit's setUpBeforeClass and tearDownAfterClass in my child classes to do some other stuff which is only related to only this child class.
But it is not working. After running tests, PHPUnit stops suddenly without throwing any errors. Kindly guide me here.
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.
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
I am not asking a typical question about why some code failed, yet I am asking about why it worked.It has worked with me while coding, and I needed it to fail.
Case
a base abstract class with a protected constructor declared abstract
a parent class extends the abstract class with public constructor (Over ridding)
a child class extends the very same abstract class with a protected constructor
abstract class BaseClass {
abstract protected function __construct();
}
class ChildClass extends BaseClass {
protected function __construct(){
echo 'It works';
}
}
class ParentClass extends BaseClass {
public function __construct() {
new ChildClass();
}
}
// $obj = new ChildClass(); // Will result in fatal error. Expected!
$obj = new ParentClass(); // that works!!WHY?
Question
Parent class instantiates child class object, and it works!!
how come it does?
as far as I know,object cannot be instantiated if its constructor declared protected, except only internally or from within any subclasses by inheritance.
The parent class is not a subclass of the child class,it doesn't inherit a dime from it ( yet both extend the same base abstract class), so how come instantiation doesn't fail?
EDIT
This case only happens with an abstract BaseClass that has also an abstract constructor.If BaseClass is concerete, or if its protected constructor is not abstract, instantiation fails as expected.. is it a PHP bug?
For my sanity, I need really an explanation to why PHP behaves this way in this very specific case.
Thanks in advance
Why it works?
Because from inside ParentClass you have granted access to the abstract method from BaseClass. It is this very same abstract method which is called from ChildClass, despite its implementation is defined on itself.
All relies in the difference between a concrete and an abstract method.
You can think like this: an abstract method is a single method with several implementations. On the other hand, each concrete method is a unique method. When it has the same name than its parent, it overrides the parent's one (it does not implement it).
So, when declared abstract, it is always the base class method which is called.
Think about a method declared abstract: Why the signatures of different implementations can't differ? Why can't the child classes declare the method with less visibility?
Anyway, you have just found a very interesting feature. Or, if my understanding above is not correct, and your expected behaviour is the truly expected behaviour, then you have found a bug.
Note: the following was tested with PHP 5.3.8. Other versions may exhibit different behavior.
Since there isn't a formal specification for PHP, there isn't a way of answering this from the point of view of what should happen. The closest we can get is this statement about protected from the PHP manual:
Members declared protected can be accessed only within the class itself and by inherited and parent classes.
Though the member may be overridden in ChildClass (keeping the "protected" specifier), it was originally declared in BaseClass, so it remains visible in descendants of BaseClass.
In direct opposition to this interpretation, compare the behavior for a protected property:
<?php
abstract class BaseClass {
protected $_foo = 'foo';
abstract protected function __construct();
}
class MommasBoy extends BaseClass {
protected $_foo = 'foobar';
protected function __construct(){
echo __METHOD__, "\n";
}
}
class LatchkeyKid extends BaseClass {
public function __construct() {
echo 'In ', __CLASS__, ":\n";
$kid = new MommasBoy();
echo $kid->_foo, "\n";
}
}
$obj = new LatchkeyKid();
Output:
In LatchkeyKid:
MommasBoy::__construct
Fatal error: Cannot access protected property MommasBoy::$_foo in - on line 18
Changing the abstract __construct to a concrete function with an empty implementation gives the desired behavior.
abstract class BaseClass {
protected function __construct() {}
}
However, non-magic methods are visible in relatives, whether or not they're abstract (most magic methods must be public).
<?php
abstract class BaseClass {
abstract protected function abstract_protected();
protected function concrete() {}
}
class MommasBoy extends BaseClass {
/* accessible in relatives */
protected function abstract_protected() {
return __METHOD__;
}
protected function concrete() {
return __METHOD__;
}
}
class LatchkeyKid extends BaseClass {
function abstract_protected() {}
public function __construct() {
echo 'In ', __CLASS__, ":\n";
$kid = new MommasBoy();
echo $kid->abstract_protected(), "\n", $kid->concrete(), "\n";
}
}
$obj = new LatchkeyKid();
Output:
In LatchkeyKid:
MommasBoy::abstract_protected
MommasBoy::concrete
If you ignore the warnings and declare magic methods (other than __construct, __destruct and __clone) as protected, they appear to be accessible in relatives, as with non-magic methods.
Protected __clone and __destruct are not accessible in relatives, whether or not they're abstract. This leads me to believe the behavior of abstract __construct is a bug.
<?php
abstract class BaseClass {
abstract protected function __clone();
}
class MommasBoy extends BaseClass {
protected function __clone() {
echo __METHOD__, "\n";
}
}
class LatchkeyKid extends BaseClass {
public function __construct() {
echo 'In ', __CLASS__, ": \n";
$kid = new MommasBoy();
$kid = clone $kid;
}
public function __clone() {}
}
$obj = new LatchkeyKid();
Output:
In LatchkeyKid:
Fatal error: Call to protected MommasBoy::__clone() from context 'LatchkeyKid' in - on line 16
Access to __clone is enforced in zend_vm_def.h (specifically, ZEND_CLONE opcode handler). This is in addition to access checks for methods, which may be why it has different behavior. However, I don't see special treatment for accessing __destruct, so there's obviously more to it.
Stas Malyshev (hi, Stas!), one of the PHP developers, took a look into __construct, __clone and __destruct and had this to say:
In general, function defined in base class should be accessible to all
[descendents] of that class. The rationale behind it is that if you define
function (even abstract) in your base class, you saying it will be
available to any instance (including extended ones) of this class. So
any descendant of this class can use it.
[...] I checked why ctor behaves differently, and it's because parent ctor
is considered to be prototype for child ctor (with signature
enforcement, etc.) only if it's declared abstract or brought from the
interface. So, by declaring ctor as abstract or making it part of the
interface, you make it part of the contract and thus accessible to all
hierarchy. If you do not do that, ctors are completely unrelated to each
other (this is different for all other non-static methods) and thus
having parent ctor doesn't say anything about child ctor, so parent
ctor's visibility does not carry over. So for ctor is not a bug. [Note: this is similar to J. Bruni's answer.]
I still think it's most probably a bug for __clone and __destruct.
[...]
I've submitted bug #61782 to track the issue with __clone and __destruct.
EDIT: constructors act differenlty... It's expected to work even without abstract classes but I found this test that tests the same case and it looks like it's a technical limitation - the stuff explained below doesn't work with constructors right now.
There's no bug. You need to understand that access attributes work with objects' context. When you extend a class, your class will be able to see methods in BaseClass' context. ChildClass and ParentClass both in BaseClass context, so they can see all BaseClass methods. Why do you need it? For polymorphism:
class BaseClass {
protected function a(){}
}
class ChildClass extends BaseClass {
protected function a(){
echo 'It works';
}
}
class ParentClass extends BaseClass {
public function b(BaseClass $a) {
$a->a();
}
public function a() {
}
}
No matter what child you pass into ParentClass::b() method, you'll be able to access BaseClass methods (including protected, because ParentClass is BaseClass child and children can see protected methods of their parents). The same behaviour applies to constructors and abstract classes.
I wonder if there isn't something buggy w/ the abstract implementation under the hood, or if there is a subtle issue going on that we're missing. Changing BaseClass from abstract to concrete produces the fatal error you're after though (classes renamed for my sanity)
EDIT: I agree w/ what #deceze is saying in his comments, that it is an edge case of abstract implementation and potentially a bug. This is at least a work-around that provides the expected behavior albiet some ugly technique (feigned abstract base class).
class BaseClass
{
protected function __construct()
{
die('Psuedo Abstract function; override in sub-class!');
}
}
class ChildClassComposed extends BaseClass
{
protected function __construct()
{
echo 'It works';
}
}
// Child of BaseClass, Composes ChildClassComposed
class ChildClassComposer extends BaseClass
{
public function __construct()
{
new ChildClassComposed();
}
}
PHP Fatal error: Call to protected ChildClassComposed::__construct()
from context 'ChildClassComposer' in
/Users/quickshiftin/junk-php/change-private-of-another-class.php on
line 46