31

I am trying to mock a class for phpunit. Php unit fails with the error Could not load mock ... class already exists. This is the only test I'm running, so it can't be the case that the class is mocked already.

Any suggestion would be appreciated.

Here is the error case:

namespace Tests\Feature;

use Tests\TestCase;

class DeactivateACSTest extends TestCase
{
    public function testDeactivateAcs()
    {
        $deviceController = \Mockery::mock('overload:App\Http\Controllers\Cloud\DeviceController');
        $deviceController
            ->shouldReceive('deactivateACS')
            ->andReturn('hilfehilfehilfe');

        $devCon = new \App\Http\Controllers\Cloud\DeviceController();
        $this->assertEquals('hilfehilfehilfe', $devCon->deactivateACS());
    }
}

When running it without --code-coverage it works:

[13:10:15] vagrant@homestead [~/Code/ekp] $ phpunit --filter DeactivateACS
PHPUnit 6.5.10 by Sebastian Bergmann and contributors.


 ==> Tests\Feature\DeactivateACSTest              ✓

Time: 1.08 seconds, Memory: 16.00MB

OK (1 test, 3 assertions)

However, when running it with --code-coverage it fails:

[13:10:23] vagrant@homestead [~/Code/ekp] $ phpunit --coverage-html coverage --coverage-text=code_coverage.txt --filter DeactivateACSTest
PHPUnit 6.5.10 by Sebastian Bergmann and contributors.


  ==> Tests\Feature\DeactivateACSTest              ⚈

Time: 5.79 seconds, Memory: 44.00MB

There was 1 error:

1) Tests\Feature\DeactivateACSTest::testDeactivateAcs
Mockery\Exception\RuntimeException: Could not load mock \App\Http\Controllers\Cloud\DeviceController, class already exists

/home/vagrant/Code/ekp/vendor/mockery/mockery/library/Mockery/Container.php:220
/home/vagrant/Code/ekp/vendor/mockery/mockery/library/Mockery.php:116
/home/vagrant/Code/ekp/tests/Feature/DeactivateACSTest.php:11

ERRORS!
Tests: 1, Assertions: 0, Errors: 1.

Generating code coverage report in HTML format ... done
Daniel Becker
  • 771
  • 1
  • 7
  • 25

2 Answers2

49

You should add these annotations before the functions that are mocking this class.

/**
 * @runInSeparateProcess
 * @preserveGlobalState disabled
 */

For reference you can check out the phpunit documentation.

https://phpunit.de/manual/current/en/appendixes.annotations.html#appendixes.annotations.runInSeparateProcess

https://phpunit.de/manual/current/en/appendixes.annotations.html#appendixes.annotations.preserveGlobalState

  • 5
    Does not work in phpunit 7.4.3 and Mockery 1.2.2. It still gives the ``Mockery\Exception\RuntimeException: Could not load mock Service, class already exists`` error. – Juha Untinen Apr 10 '19 at 10:15
  • 1
    Great trick! This worked perfectly with PHPUnit 9.5 and Mockery 1.4 for a test class where I was using several instance mocks with the `overload` prefix. Ultimately I ended up using the `@runTestsInSeparateProcesses` annotation on the whole class for simplicity. (In my case `@preserveGlobalState` wasn't actually needed... YMMV). – Andron Mar 03 '21 at 22:11
  • Update... turns out that that particular test class could run without `@preserveGlobalState disabled`, but I had to add it to the class comment to get the whole test suite to run properly. – Andron Mar 04 '21 at 13:53
1

I ran into the same issue and fixed like this:

  1. There was another test in my unit tests (not mockery test) which had require_once on the PHP file that had the class I was mocking. I've removed that line.
  2. I've added processIsolation="true" in test suite
Gander
  • 1,854
  • 1
  • 23
  • 30
Vivek G
  • 21
  • 2