Mockery fails with 'Could not load mock ... class already exists' when running with --code-coverage
Asked Answered
M

2

36

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
Merrimerriam answered 6/8, 2018 at 13:1 Comment(1)
the same problem how did you resolve it?Pechora
I
56

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

Invasion answered 12/11, 2018 at 17:11 Comment(3)
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.Raconteur
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).Dominations
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.Dominations
B
2

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
Biforked answered 8/8, 2019 at 16:57 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.