1

When I run phpunit, my fixtures are null. I initialize the fixtures in setUp(), but my debugging has shown it is never called. I tried having the member variables be assigned the proper values in the child class, but they remain null, which boggles my mind.

// Unit/Base.Unit.php 
Class BaseUnit extends PHPUnit_Framework_TestCase {
  // Tests for Base Object methods
}

// Unit/Validation/Validation.Unit.php
Class ValidationUnit extends BaseUnit {
  protected $validationClass;
  protected $validData;
  protected $invalidData;

  protected function newValidationInstance($data) {
    return new $this->validationClass($data); 
  }

  public function testValidData() {
    $instance = $this->newValidationInstance($this->validData);
    $this->assertEquals('true', $instance->isValid());
  }
  // ... other tests for validation ...
}

// Unit/Validation/Email.Test.php
Class EmailTest extends ValidationUnit {
  protected function setUp() {
    $this->class = "Email";
    $this->validData = "test@gmail.com";
    $this->invalidData = "fdksljfa"; 
  }
}

Running PHPUnit...

phpunit --bootstrap /some/config.php Unit/

PHPUnit 4.2.2 by Sebastian Bergmann.

.E
Fatal error: Class name must be a valid object or a string in /opt/bitnami/some/path/Unit/Validation/Validation.Unit.php on line 9

What I'm expecting to happen is for phpunit to start tests on EmailTest, and run the tests both in it and it's parent classes. The Validation class has a ton of subclasses (Email, ZipCode, etc) so having all the testing in Validation is a huge win.

But I can't call setUp(), so I can't instantiate the proper Validation classes.

Edit

So it turns out that setUp() is called before any tests in the class that setUp() is defined in but not before other tests, including tests in parent classes.

So in order to control the order of tests, I'm having each class define an invokeTests() function containing it's tests, and then calling it's parent's invokeTests() method. That way, tests will be executed with respect to OO hierarchy.

PandemoniumSyndicate
  • 2,855
  • 6
  • 29
  • 49
  • It won't call the setUp method from the child class. The way you have your classes written, you shouldn't be running the parent classes. To ignore the parent classes check out: http://stackoverflow.com/questions/5934347/mark-a-phpunit-test-class-as-to-be-ignored – Tyler Marien Aug 28 '14 at 22:41
  • 1
    Why won't it call setUp() from the child class? Why shouldn't I run the tests in parent classes? That's where all the test logic is. If you mean that they shouldn't be picked up by phpunit cli, I'm pretty sure they're not since the parent classes filesnames are *.Unit.php, and the Email test is Email.Test.php, which means they are ignored by phpunit's search for tests. – PandemoniumSyndicate Aug 28 '14 at 22:51
  • Inheritance doesn't work that way. Parent classes don't know what is defined in their child classes. What would happen if you defined two child classes with 2 implementations of setUp? – Tyler Marien Aug 28 '14 at 22:54
  • As far as the way you are writing your test, you are trying to make it too generic. Just write the test in EmailTest with the appropriate class and data. – Tyler Marien Aug 28 '14 at 22:55
  • So it *should* override setUp(), and EmailTest extends ValidationUnit extends BaseUnit extends PHPUnit_Framework_TestCase, so EmailTest should be a PHPUnit_Framework_TestCase. Are you saying that PHPUnit is trying to do PHPUnit_Framework_TestCase->setUp() rather than EmailTest->setUp()? – PandemoniumSyndicate Aug 28 '14 at 23:01
  • Correct. ValidationUnit will call PHPUnit_Framework_TestCase->setUp() which does nothing. Therefore $this->newValidationInstance and $this->validData are both undefined when ValidationUnit->testValidData is called. – Tyler Marien Aug 28 '14 at 23:18
  • 1
    Ahh! Seem to have found the issue. setUp() is called before any tests *in that class*, but not necessarily before other tests, including those defined in their superclasses. I think this makes sense since PHPUnit does some meta-magic of calling functions based on their name, not on the hierarchical relations. – PandemoniumSyndicate Aug 29 '14 at 00:41
  • This contradicts the general principle of inheritance in OOP. You could refactor your functionality into traits, then use the traits in the actual tests. I'm doing this extensively and as far as I can tell it's working. – Jay Bienvenu Jan 13 '18 at 23:25

0 Answers0