简体   繁体   中英

PHPUnit Dependency Injection Into A TestCase

I was wondering whether it's possible to inject dependencies into classes derived from PHPUnit_Framework_TestCase via eg some context test suite - in a manner that PHPUnit could handle irregardless whether it has been invoked manually, with a phpunit.xml configuration file or else?

Please consider the following example:

<?php
interface AnyGreeter {   
    public function greet($recipient);
}   

class FriendlyGreeter implements AnyGreeter {   
    public function greet($recipient) {   
        return "Hello {$recipient}!";
    }   
}   

class DorkGreeter implements AnyGreeter {
    public function greet($recipient) {   
        return "Get lost, {$recipient}!";
    }   
}

Now I want to provide some general test for classes implementing AnyGreeter , eg:

<?php
class GeeterTest extends PHPUnit_Framework_TestCase {

    public function testGreet() {   
        $greeter = $this->getGreeter();
        $message = $greeter->greet("world");
        $this->assertContains("world", $message);
    }   

    public function setGreeter(AnyGreeter $greeter) {   
        $this->greeter = $greeter;
    }   

    public function getGreeter() {   
        if (null === $this->greeter) {
            $this->markTestSkipped("No greeter provided");
        }   
        return $this->greeter;
    }

    private $greeter;
} 

This may get re-used by my own as well as any future implementations (which I do not control).

How is this possible, especially in a project that relies on interfaces heavily? I don't want to write abstract tests and extend them for every single implementation --

Thanks!

I have never seen this done, and there's nothing in the docs. Seems a bit complex for a test. I'd solve your problem by using a data provider to pass greeter objects to the testGreeter method, then all you have to do is maintain an array of concrete greeter classes in the provider.

See the 'data provider' section here: http://www.phpunit.de/manual/3.2/en/writing-tests-for-phpunit.html

I think your best approach would use providers as mentioned by Glen:

class GreeterTestCase extends PHPUnit_Framework_TestCase
{
    protected function getGreeter()
    {   
    }   

    /** 
     * @dataProvider providerGreeter
     */
    public function testGreet(AnyGreeter $greeter)
    {   
        $message = $greeter->greet('world');
        $this->assertType('string', $message, 'AnyGreeter::greet() must return string');
        $this->assertContains('world', $message);
    }   

    public function providerGreeter()
    {   
        return array(array($this->getGreeter()));
    }   
}

This way, other parts of the library can extend this test case to test their own implementation meets the basic interface spec. Any of their custom unit tests specific to that implementation go in the extended test case.

Now you have a choice of testing a single implementation (which may have its own unit tests), or just grouping together a load of implementations to get the default tests:

class AnyGreeterTestCase extends GreeterTestCase
{
    public function providerGreeter()
    {
        return array(
            array(new FriendlyGreeter()),
            array(new DorkGreeter()),
        );
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM