Skip to content

Unit tests can't mock final MoneiApiClient — extract interface #2

Description

@alexandresaiz

Problem

`phpunit` fails on main across all PHP/Sylius matrix combinations with 10 errors:

```
PHPUnit\Framework\MockObject\Generator\ClassIsFinalException:
Class "Monei\SyliusPlugin\Client\MoneiApiClient" is declared "final" and cannot be doubled
```

The affected tests are `tests/Unit/Action/StatusActionTest.php` and `tests/Unit/Action/RefundActionTest.php`, which call `$this->createMock(MoneiApiClient::class)`. PHPUnit 10 enforces that `final` classes cannot be doubled.

Static analysis is also red — PHPStan reports 4 errors including `Cannot call method jsonSerialize() on class-string|object`.

Design intent vs. current state

The class docblock states:

Isolates the SDK from Payum's action layer so that:

  • Actions depend on a mockable interface, not a concrete SDK class.

But the class is a concrete `final class` with no interface. The intent was never implemented.

Recommended fix

  1. Extract `MoneiApiClientInterface` covering the methods the Payum actions call (`createPayment`, `getPayment`, `refundPayment`, etc.).
  2. Have `MoneiApiClient implements MoneiApiClientInterface`.
  3. Typehint Payum actions against `MoneiApiClientInterface`, not the concrete class.
  4. Update tests to `createMock(MoneiApiClientInterface::class)` — then `MoneiApiClient` can stay `final` as originally intended.
  5. Fix the 4 PHPStan errors separately (mostly narrowing `class-string|object` unions).

Why not quick-patch

Removing `final` would unblock mocks but directly contradicts the documented design. Not a sustainable fix.

Context

CI has been red since the initial commit on 2026-04-11. Plugin runtime behavior is unaffected — only test-time failures.

Last failing run: https://github.com/MONEI/SyliusMoneiPlugin/actions

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions