Giter Site home page Giter Site logo

Comments (2)

gmazzap avatar gmazzap commented on May 22, 2024

Hi @dingo-d

let's go in order.

Test remove_action / remove_filter

Your example is correct. As documented, you can use has_filter like you'd do in WordPress, so if you have code that remove an hook, at the end of the test you can use has_action / has_filter to test it was actually removed.

Another possible way is to re-define remove_filter yourself and use expectations on it:

public function test_allowed_rest_headers() {
    
    Functions\expect( 'remove_filter' )
         ->once()
         ->with( 'rest_pre_serve_request', 'rest_send_cors_headers' );

     Filters\expectAdded( 'rest_pre_serve_request' )
         ->once()
         ->with( \Mockery::type( \Closure::class ) );

    (new My_Class())->set_allowed_rest_headers();
}

This is not more nor less "correct" then the way you are using, it is just different, you can do what better fits your taste.

Code coverage

That is the expected behavior. The closure that is added to the filter is not executed. The call to add_filter is executed, passing that closure as argument, but the closure itself never runs.

In other words, with this test (no matter how do you write it), you are testing that the filter is added, not that callback added to the filter is executed.

And that also what WordPress does: when you call add_filter WordPress does not execute the callback, in fact, the callback might be never executed if the matching apply_filters is executed or if matching apply_filters was executed before the add_filter call.

If you really want to execute the function you could do:

Filters\expectAdded( 'rest_pre_serve_request' )
    ->once()
    ->whenHappen( function ( $callback ) {
        $callback();
    });

And that would execute the function so your coverage turns green, but:

  • are you sure you want to execute header calls inside a test?
  • the fact the callback is excuted does not / should not change the result of the test: again, you are testing that the filter is added, and test already passed
  • the fact that the coverage is red is correct: with this test the correctness of the anonymous function is not tested. You can cheat and make coverage become all green... but that would be misleading: if you want to test the callback correctness, you have to test the callback, not the fact that the callback is added to a filter.

How do you test an anonymous function?

Actually, you really can't, not in unit testing. Yes, there might be way to execute the callbacks... but the test becomes hard to read and maintain.

This is why you should use anonymous function for things that are logic-free or maybe wrapper to other callbacks you can test separately.

E.g. if you have a code like:

add_filter( 'rest_pre_serve_request', function( $value ) {

    $sender = MyCustomHeadersSender();
    return $sender->send();
}

The 2 lines of the anonymous function will not be covered by the tests, but that's not a big issue if MyCustomHeadersSender class is tested separately.

Complex logic in anonymous function should really be avoided. When an anonymous function start growing is probably time to extract to a separate function (or class or method).

In your case, I think that usage of anonymous function is totally fine. But because of the nature of the anonymous function, which is directly interacting with HTTP layer, you should not test it in unit tests, but in a tests that executes the code in HTTP context, loading WordPress.

Unit tests do not replace integration / system / end-to-end tests... Unit tests are one of the kind of software testing, one that is surely important because enable fast development iteractions, but they are not the only kind of test, and more often than not they not suffice to ensure correctness of the software, expecially if the software interacts with side effects, complex output or different application layers like HTTP or database.

from brainmonkey.

dingo-d avatar dingo-d commented on May 22, 2024

First of all, thanks for the detailed answer :) I'm a bit of a newbie when it comes to testing, so I'm not all clear on some things. Your answer helped a lot.

I was suspecting I cannot test the anonymous functions but just wanted to be clear. I will add integration tests after I finish writing the unit tests because I'll need to mock a lot of things in the integration tests later on (I'm basically using WP for backend only so there are a lot of things to test).

Once I add the integration tests for the headers, these lines should become green, no?

I was even thinking of rewriting the function with the headers as a separate private function and adding it to the add_filter, but I'm not sure if this will work correctly (will have to test this, no pun intended :D ).

As for unit testing headers, I think that would have to be mocked (I might be wrong), but then the test wouldn't make much sense, as you mentioned. I'll just explain to the client that some things cannot be fully tested, but if the front end app works (which it does) it's basically a test so it's all ok :)

Thanks again for the great answer.

from brainmonkey.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.