10up / wp_mock

WordPress API Mocking Framework
https://wp-mock.gitbook.io
Other
676 stars 70 forks source link

Mocked user function remains mocked in separate test. #238

Closed petermorlion closed 9 months ago

petermorlion commented 10 months ago

Bug report

This could be me doing something wrong, but what I'm experiencing is a mocked user function being "remembered" across two tests.

Replication steps

Create a class to test:

public class Foo
{
    public static function get_current_datetime() {
        return current_datetime()->format('Y-m-d');
    }
}

Create a test class:

use PHPUnit\Framework\TestCase;

final class FooTest extends TestCase
{
    public function test_1(): void
    {
        WP_Mock::userFunction('current_datetime')->andReturn(new DateTimeImmutable('1999-01-01'));

        $result = Foo::get_current_datetime();

        $this->assertEquals('1999-01-01', $result);
    }

    public function test_2(): void
    {
        WP_Mock::userFunction('current_datetime')->andReturn(new DateTimeImmutable('2024-01-01'));

        $result = Foo::get_current_datetime();

        $this->assertEquals('2024-01-01', $result);
    }

}

Run the tests (in strict mode, although I didn't see any difference with or without strict mode).

Expected behavior

I expect both tests to pass, yet the second tests fails because the $result is 1999-01-01, i.e. the result of the first test. Switch the order of the tests and you get the same issue the other way around. Run any test by itself and it passes.

I've used older mocking frameworks (in other languages) in the past where you had to do a reset of all mocks explicitly, but I didn't find this documented about WP_Mock anywhere. I tried WP_Mock::setup() and WP_Mock::tearDown() calls, but that didn't make a difference.

Logs

Log ``` .F 2 / 2 (100%) Time: 00:00.033, Memory: 10.00 MB There was 1 failure: 1) FooTest::test_2 Failed asserting that two strings are equal. --- Expected +++ Actual @@ @@ -'1999-01-01' +'2024-01-01' C:\Users\peter\source\repos\... FAILURES! Tests: 2, Assertions: 2, Failures: 1. ```
ajaynes-godaddy commented 10 months ago

Hi @petermorlion:

I can confirm the second test fails when extending PHPUnit\Framework\TestCase as you have, though it passes if extending WP_Mock's version of TestCase, which likely points to a bootstrapping issue.

Would you mind sharing the contents of your bootstrap.php file?

petermorlion commented 10 months ago

Aha, interesting. Although the docs also extend from PHPUnit's TestCase, I believe?

This is my bootstrap.php:

<?php

// First we need to load the composer autoloader, so we can use WP Mock
require_once dirname(__DIR__) . '/vendor/autoload.php';

// Bootstrap WP_Mock to initialize built-in features
WP_Mock::activateStrictMode();
WP_Mock::bootstrap();

// Define base path
define('WFM_BASE_PATH', dirname(__DIR__) . '/src/');

(the last part is just setting a constant my code sometimes needs)

unfulvio-godaddy commented 10 months ago

@petermorlion

try to add this line before activateStrictMode:

WP_Mock::setUsePatchwork(true);

edit: sorry probably not needed in your case if you are just using the userFunction method, sounds like @ajaynes-godaddy suggestion is more on point, and perhaps there's a misconfiguration with WP_Mock and/or PHPUnit that may be causing the issue you're seeing

ajaynes-godaddy commented 10 months ago

Aha, interesting. Although the docs also extend from PHPUnit's TestCase, I believe?

You're correct. We're actually trying to figure out if there's a undocumented dependency in play here, so knowing how you're bootstrapping gives more insight.

Sorry if it seemed like was implying it was something wrong with your setup, mostly trying to figure out where there's a potential mismatch when using PHPUnit\Framework\TestCase vs WP_Mock\Tools\TestCase 😉

petermorlion commented 10 months ago

If you want, I created a reproducable sample project. In my project, I use wp_mock 0.4.2 and the sample uses 1.0 but the issue remains either way.

I tried @unfulvio-godaddy 's tip of using Patchwork, but that didn't solve it.

Indeed, if I extend WP_Mock\Tools\TestCase, the tests pass.

unfulvio-godaddy commented 9 months ago

@petermorlion the reason the tests are failing is that your are extending PHPUnit's TestCase class -- please extend \WP_Mock\Tools\TestCase instead OR ensure you are calling WP_Mock::teardown() between tests, by adding this method:

    public function tearDown() : void
    {
        parent::tearDown();

        WP_Mock::tearDown();
    }

Once I apply either change in your test project, the tests are passing and not producing an error anymore.

We need to make this more clear in the docs for people who don't wish to extend WP_Mock provided TestCase class.

petermorlion commented 9 months ago

Extending WP_Mock's TestCase fixed it (and using WP_Mock 1.0 with PHPUnit 9.6). Thanks for the help!