Dawid Ohia
Dawid Ohia

Reputation: 16455

Dependent tests between two TestCase classes in PHPUnit

In PHPUnit you can make one test to be depend on other test by using @depends annotation. Is it possible to make whole TestCase dependent on test in other TestCase? Or at least make single test in one TestCase dependent on test in other TestCase?

I tried:

/**
 * @depends A::testMethodName
 */

But as I expected it doesn't work.

Update:

The exact situation looks like this: There is class B which uses class A. So I want to test B only if the tests for A (or one of it's tests) run without a failure. How can I do that?

Upvotes: 18

Views: 22719

Answers (4)

Josh Woodcock
Josh Woodcock

Reputation: 2803

Exploiting dependencies are extremely important! The loose coupling as referred to is for actual application architecture not for unit test cases. If there is logical dependencies built in to functional execution is is always a good idea to exploit those dependencies.

Using test doubling is appropriate for SOA where dependencies cannot be mapped to a particular failure within a black box AND the service is not reliable. This is not appropriate for inter application classes.

You definitely would want to use this type of functionality if there is logical dependencies between test classes. The concept to be grasped from unit testing is it's ability to isolate defects to particular components immediately.

This functionality IS available on PHPUnit v 3.7.13. However, the only way this will work is if you run PHPUnit on a directory which contains both TestCase classes.

For example with this folder structure

- application\dep
   |- BTest.php
   |- CTest.php

The classes...

class BTest extends PHPUnit_Framework_TestCase
{
    /**
     * @depends CTest::testADomino
     */
    public function testDominoDependent()
    {
        $this->assertTrue(true);
    }
}

and...

class CTest extends PHPUnit_Framework_TestCase
{
    public function testADomino()
    {
        $this->assertTrue(false);
    }
}

This is the result

C:\Users\Josh>C:\xampp\php\phpunit.bat "C:\xampp\htdocs\BeAgile\applications\sto
cklogger\tests\dep"
PHPUnit 3.7.13 by Sebastian Bergmann.

SF

Time: 0 seconds, Memory: 2.00Mb

There was 1 failure:

1) CTest::testADomino
Failed asserting that false is true.

C:\xampp\htdocs\BeAgile\applications\stocklogger\tests\dep\CTest.php:7

FAILURES!
Tests: 1, Assertions: 1, Failures: 1, Skipped: 1.

You could have both test case classes in the same file but that would be a poor structure. It is not necessary to "make sure" one test runs before the other.

As an agile coach I see test doubling far too often in large organizations where specialized segments want to avoid having build failures when another components makes changes that causes test failure. This of course defeats the entire purpose of the unit tests which is to identify component failures before the end user does.

Upvotes: 15

Ekown
Ekown

Reputation: 438

For those who are still wondering about this question, you can use the @Dependsreference instead of the @depends. It seems that the lowercase version can only be used in an inter-functional manner while the capital can be used class-to-class.

/**
 * @Depends FirstTest::testMethodName
 */

Make sure that the depended test class will be run before the actual test class that depends on it. You can do this by declaring the order of the test classes in the testsuite in the phpunit.xml.

<phpunit
        bootstrap="./vendor/autoload.php"
        colors="true"
>
    <testsuites>
        <testsuite name="App\\Tests">
            <directory>./test</directory>
        </testsuite>
        <testsuite name="sample-testsuite">
         <directory>./test/FirstTest.php</directory>
         <directory>./test/SecondTest.php</directory>
        </testsuite>
    </testsuites>

    <filter>
        <whitelist processUncoveredFilesFromWhitelist="true">
            <directory suffix=".php">src</directory>
        </whitelist>
    </filter>
</phpunit>

Then, you run the testsuite.

./vendor/bin/phpunit --testsuite sample-testsuite

I have only tested this with 6.1.0+ versions. You can see the discussion about this issue here. Thanks :)

Upvotes: 8

Theodore R. Smith
Theodore R. Smith

Reputation: 23257

It sounds like your tests are integrative, instead, and fail if distinct subsets are broken. I would encourage you to look up Mocks and Stubs. Only those are the proper answers to your question. Don't fall for hackish workarounds that will only hurt you in the long run.

http://phpunit.de/manual/3.6/en/test-doubles.html

Upvotes: -2

David Harkness
David Harkness

Reputation: 36562

There's no built-in way to do this, but it wouldn't be hard to have any number of tests depend on some other test passing. You must ensure that ATest is executed before BTest.

class ATest extends PHPUnit_Framework_TestCase {
    public static $passed = false;

    function testThatMustPass() {
        // ... the actual test ...
        // ok, test passed
        self::$passed = true;
    }
}

class BTest extends PHPUnit_Framework_TestCase {
    function testThatDependsOnA() {
        if (!ATest::$passed) {
            self::markTestSkipped('A failed');
        }
    }
}

Having tests depend on an entire test case is also possible.

class ATest extends PHPUnit_Framework_TestCase {
    public static $passed = true;

    protected function onNotSuccessfulTest(Exception $e)
        self::$passed = false;
        parent::onNotSuccessfulTest($e);
    }
}

You could improve these by tracking the names of the tests that failed so you could depend on a subset of tests for each case.

Upvotes: 7

Related Questions