3

I have a PHPUnit test testFoo() with a dataProvider fooProvider(). At the beginning of testFoo() I'm using Runkit to redefine a method so I can test expected results when that method is returning what I've redefined it to return. However, redefining the method is a little time-intensive, so I'd like for it to only happen once for this test.

Does the PHPUnit framework provide functionality to specify code that I'd like to run just once before testFoo() runs and not once for each element returned by fooProvider() or once per test in the suite (as with setUp())?

thanksd
  • 54,176
  • 22
  • 157
  • 150
  • how about [@beforeClass](https://phpunit.de/manual/current/en/appendixes.annotations.html#appendixes.annotations.beforeClass) ? – xmike Mar 07 '16 at 18:20
  • @xmike I need to redefine said method multiple times to return different things for different tests, so it really needs to be specific to the individual test – thanksd Mar 07 '16 at 18:58
  • than I would stay with your `@before` but imlement my own provider doing inside the test smth like `$dataSets = $this->getDataSets()` (supposed to return the array of your data) and then loop through it with assertions inside the loop. This way the test will be started by PHPUnit framework only once so `setUp()` will be run once only, too (from it's point of view test will be run only once). – xmike Mar 07 '16 at 19:11
  • I guess I'm hoping for a `@beforeTest` annotation to specify a function to run once before the test so I wouldn't need to clutter up my test methods with the loop and reference setting. But from what I can see from PHPUnit documentation that doesn't exist? – thanksd Mar 08 '16 at 14:45
  • well actually you're right and `@before` is run just once before each test. The thing is that if you use `@dataProvider` the test is relaunched for each data set thus making `@before` to be executed also -- that's the way PHPUnit framework deals with data providing (this happens because the test must be invoked with each new data set and receive that new set as arguments). So the way to avoid relaunching is not to use automated dataProviding. – xmike Mar 08 '16 at 19:54

1 Answers1

3

Use a static private property to flag that the method has been redefined. You need it to be static because the test class is instantiated for each case provided by the dataProvider.

class FooTest extends PHPUnit_Framework_TestCase
{
    private static $redefined = false;

    /**
     * @dataProvider fooProvider
     */
    public function testFoo()
    {
        if (! self::$redefined) {

            // redefinition code goes here

            self::$redefined = true;
        }
    }
}
gontrollez
  • 6,372
  • 2
  • 28
  • 36
  • I was hoping for a solution from within the PHPUnit framework (I'll edit my question to clarify that). I'm redefining the same methods in different tests and it'd be nice to not have to manually keep track of each method and whether is has been redefined and also redefined to the appropriate substitute method for each test. – thanksd Mar 09 '16 at 14:32
  • In that case you can have a class that handles the method redefinitions and is used from all the tests. That class should know what methods have been already redefined and do nothing in case the method is already redefined. – gontrollez Mar 09 '16 at 14:46
  • That would work, but would be a pretty roundabout way of preventing a method from getting redefined multiple times (compared to xmike's workaround in the question's comments or compared to some function similar to `setup()` from within the PHPUnit Framework) – thanksd Mar 09 '16 at 15:01