Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Best approach to mock functions after require_once. #137

Closed
aaronfc opened this issue May 19, 2023 · 2 comments
Closed

Best approach to mock functions after require_once. #137

aaronfc opened this issue May 19, 2023 · 2 comments

Comments

@aaronfc
Copy link

aaronfc commented May 19, 2023

Hey,
I have been using BrainMonkey recently (thanks for it!).

I have the following piece of code at the end of a method I want to cover with unit tests:

// ...
require_once ABSPATH . 'wp-admin/includes/upgrade.php';
dbDelta( $sql );
// ...

In the test I am adding this expectation:

Functions\expect( 'dbDelta' )->once();

I think it's quite common to have some WP methods that require an explicit require_once (because they are not loaded by default, like in this case).

At the moment I am extracting that piece of code into a separate function (under my namespace) and then I am just using this method from my original code and patching it in the test. But I was wondering if there is any better alternative?

This is my current approach:
functions.php

namespace Aaron;

function dbDelta() {
  require_once ABSPATH . 'wp-admin/includes/upgrade.php';
  \dbDelta( $sql );
}

code.php

\Aaron\dbDelta( $sql );

test.php

Functions\expect( 'Aaron\dbDelta )->once();
@gmazzap
Copy link
Collaborator

gmazzap commented May 22, 2023

Hi @aaronfc

Writing a wrapper for functions to mock is not an uncommon practice, especially for projects like WordPress code that do not implement autoloading for objects and make large use of functions (not auto-loadable).

There are people who advocate always doing it, and that popularized a saying "Don’t Mock What You Don’t Own" (a concept which, I think was first introduced in this paper: http://jmock.org/oopsla2004.pdf).

Regardless you agree or not with that idea, doing it in your specific case does not seem too bad to me.

An alternative you might consider is to change your code to:

// ...
if  (defined('ABSPATH') && ! function_exists('dbDelta')) {
    require_once ABSPATH . 'wp-admin/includes/upgrade.php';
}
dbDelta( $sql );
// ...

It works because when you let Brain Monkey mock the function, it'll declare the function for you, so the condition will always be false in your tests, even assuming you define ABSPATH there.

Sure, function_exists adds some overhead to the execution, but considering I'm not expecting you're calling this code on every request and surely (I hope) in nothing "performance critical", then you might be okay in this teeny tiny overhead.

Please note: I'm not saying this is better or worse approach, it's just another approach.

@gmazzap gmazzap closed this as completed May 22, 2023
@aaronfc
Copy link
Author

aaronfc commented May 22, 2023

Thanks for the detailed answer :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants