6

Here is my problem.

I have a test suite that is testing a few classes. My classes all use dependency injection.

I have a class called scheduleHandler that passes all tests. Then my other class ruleHandler has a method that requires an instance of scheduleHandler. I dont want to pass in the real scheduleHandler so I tried to create a mock scheduleHandler to inject in.

The problem I have is that because the scheduleHandler class is tested in the suite above ruleHandler, when the mock is created I get:-

PHP Fatal error:  Cannot redeclare class scheduleHandler

If I dont use a test suite, and run the tests individually everything is fine.

Anyone know of a way to get round this ?

SteveG
  • 183
  • 1
  • 3
  • 9
  • $mockScheduler = $this->getMock('scheduleHandler'); – SteveG Oct 12 '11 at 15:51
  • It works if I change the order in the test suite : $this->addTestSuite('scheduleHandlerTest'); $this->addTestSuite('ruleHandlerTest'); Very strange.... – SteveG Oct 12 '11 at 15:54
  • 1
    can you put a var_dump(class_exists('scheduleHandler', false)); before the $this->getMock call please? Just to see if my assumption has any merit – edorian Oct 12 '11 at 16:12
  • 1
    Can you confirm `var_dump(get_class($this->getMock('scheduleHandler')))` gives you something like `scheduleHandlerTest_` – Mike B Oct 12 '11 at 16:47
  • @Mike B: Yeap I do get that result:- object(Mock_scheduleHandler_47ab6dd0)#208 (3) { ["invocationMocker:protected"]=> NULL ["_observer:private"]=> array(0) { } ["_db:private"]=> NULL } – SteveG Oct 13 '11 at 07:19
  • @edorian This returns boolean(false) var_dump(class_exists('scheduleHandler', false)); $mockScheduler = $this->getMock('scheduleHandler', array(), array(), '', false); – SteveG Oct 13 '11 at 07:26
  • Have you tried to run it with --process-isolation? – Ramon Poca Oct 15 '11 at 14:24

3 Answers3

5

My best guess so far:

var_dump(class_exists('scheduleHandler', false)); 

returns false for you. That means the class doesn't exist yet. Now if you autoloader doesn't find the class when phpunit is trying to extend from it phpunit will create the class it's self.

If you later down the road then require the REAL class from somewhere those to classes will collide.

To test this make sure you have required your REAL scheduleHandler class BEFORE creating the mock object.

edorian
  • 38,542
  • 15
  • 125
  • 143
  • Yes, as mentioned previously, it does work with the real scheduleHandler being above the ruleHandler (which has the mock) in the test suite. I'm not using an autoloader with these tests. It does all work, but I dont like how it breaks if the order is changed. Cheers – SteveG Oct 13 '11 at 15:44
  • So my suggestion is to require_once the real class before creating the mock. --- There is pretty much nothing else you can that i know of to avoid this behavior. – edorian Oct 14 '11 at 07:23
  • Yeah, thats about all I can do. I will revisit this and try and work out what is causing the re-declare when I have more time. Thanks for everyone's input ! – SteveG Oct 14 '11 at 09:44
  • 1
    The redeclaration is caused exactly as edorian stated: you are manually including the class's module *after* telling PHPUnit to declare the class itself (by calling `getMock()` before the class exists). An autoloader will save you so much effort and headache, it's just plain silly not to use one. :) – David Harkness Oct 19 '11 at 02:35
3

Try using namespaces in Mock creation. If you don't use them in your project code then hopefully it will override global namespace and not cause conflict

$this->getMock('\SomeTestingFramework\SomeTestClass\scheduleHandler');

Artjom Kurapov
  • 6,115
  • 4
  • 32
  • 42
0

Try $this->getMock('scheduleHandler', array(), array(), '', false). That will cause PHPUnit to skip calling scheduleHandler::__construct, which probably caused the error by loading a class twice.

Tgr
  • 27,442
  • 12
  • 81
  • 118
  • Nope, no difference. PHP Fatal error: Cannot redeclare class scheduleHandler in /var/www/fleetManagement/models/scheduleHandler.class.php – SteveG Oct 13 '11 at 07:22
  • Could you put something like `echo '!!!'; die;` after the getMock call, to see if that line causes the fatal error, or if it happens later? – Tgr Oct 13 '11 at 09:25
  • The above doesnt get echoed out, the fatal error happens first. – SteveG Oct 13 '11 at 15:53
  • That is weird - with the fifth paramter set to false, `getMock()` should not invoke anything in your code, so it should not be able to result in a fatal error. Maybe you are using a very old version of PHPUnit which does not have that option - could you check `phpunit --version`? You could also try calling `$this->getMock('scheduleHandler', array(), array(), '', false, false, false)` to disable autoloading and calling `__clone` - neither should be relevant here, but worth a try. – Tgr Oct 16 '11 at 08:41
  • Thanks. I tried that, and its just the same. Here is the version output :- PHPUnit 3.5.15 by Sebastian Bergmann. – SteveG Oct 18 '11 at 08:02