alobeejay
alobeejay

Reputation: 257

phpunit - Mock external static methods

I am desperately trying to unit test a module for a shopsystem. That shop system uses static methods which I have to call in my functions I want to test.

public function toTest() {
    $value = \Context::getData();
    return $value;
}

Now how can I unit test that function while mocking this static call? I tried using AspectMock but that does not work because it apparently needs access to the original \Context class which is not available since it's an external system. I also tried using class_alias to create my own Context class but that does not work either because I need different Context output depending on which function I am testing. And setting class_alias multiple times for different tests does not work because the same class can't be declared multiple times and @runTestsInSeparateProcesses did not have the expected effect.

Edit: None of the duplicates provided a viable solution to my situation, so I don't think this is a duplicate. With no access to the shopsystem code and especially with hard to maintain code like that, PHP does not make it easy to unit test this. Also the solution I found should help others with similar settings.

Upvotes: 5

Views: 8971

Answers (1)

alobeejay
alobeejay

Reputation: 257

I could solve my issue with the Mockery library. I tried out a few but nothing worked. With Mockery everything seems possible now. This link really helped: https://robertbasic.com/blog/mocking-hard-dependencies-with-mockery/

You can easily mock static calls to classes that don't belong to you:

public function methodToTest() {
    return \Context::getData();
}

public function testMethodToTest() {
    m::mock('alias:\Context')
        ->shouldReceive('getData')
        ->andReturn('foo');
}

And even instantiations for classes you don't have access to:

public function methodToTest() {
    $obj = new \Category(5);
    return $obj->id;
}

public function testMethodToTest() {
    m::mock('overload:\Category')
        ->shouldReceive('__construct')
        ->with(5)
        ->andSet('id', 5);
}

But you have to keep in mind that you need the two phpunit annotations at the beginning of the class:

* @runTestsInSeparateProcesses
* @preserveGlobalState disabled

Upvotes: 4

Related Questions