简体   繁体   中英

Adding interface to mock with Mockery (hard dependency)

I need to mock CurrencyEnum by overload it, but it's not the end becouse i need to add interface to this mock. This doesn't work:

Mockery::mock('overload:'.CurrencyEnum::class);

Error: (..) must be an instance of \\BaseCurrency, instance of \\CurrencyEnum given . I looked at Mockery\\Container::mock and I dont't have idea how to do it. In example I want to test TestingClass::first() method

class CurrencyEnum implements BaseCurrency
{
    /* methods */
}


class TestingClass
{
    public function first(string $currencySymbol)
    {
        $abc = 'some_string';

        return $this->second($abc, new CurrencyEnum($currencySymbol));
    }

    private function second(string $abc, BaseCurrency $currency)
    {
        /* code */
    }
}

The overload method works by intercepting the autoload mechanism: it registers an autoloader for the overloaded class, loading the mocked version of the class instead of the original. By default, it does not add many things to the mocked class. You can, however, configure just about anything you may need.

Usually, implementing one or more interfaces can be done by providing a comma-separated list of fully qualified names, the first one being the class:

$mock = Mockery::mock('MyClass, MyInterface, OtherInterface');

Due to the way that the Mockery::mock method is set up, this will not work. ( The author apologises in the source code )

However, we can pass the interface(s) as second argument to the mock method:

Mockery::mock('overload:'.CurrencyEnum::class, BaseCurrency::class);

This will cause the MockConfigurationBuilder to add BaseCurrency as target; since it's an interface it will make the mock implement the interface.

An alternative notation of the above would be to use the builder directly:

Mockery::mock(
    (new MockConfigurationBuilder())
        ->setInstanceMock(true)
        ->setName(CurrencyEnum::class)
        ->addTarget('stdClass')
        ->addTarget(BaseCurrency::class)
)

Having said that, it's a notoriously bad practice to mock things like enums and value objects. Why not just use the actual CurrencyEnum ? Something as simple as a currency code does not quite warrant mocking at all. There's probably a structural improvement to make, which would simultaneously add tons of value to your tests and make them simpler to read.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM