Comments (2)
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.
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)
- Release 2.6.1 ? HOT 15
- The file that defines <Namespace::method> was included earlier than Patchwork. This is likely a result of an improper setup; see readme for details. HOT 2
- Add more utilities to stub WordPress functions HOT 3
- Old site? HOT 4
- A never-returning function must not return in ... HOT 10
- Best approach to mock functions after require_once. HOT 2
- Issue with mocking my functions (Wordpress) HOT 4
- Expects not functioning HOT 2
- How to set expectations for inside anonymous functions HOT 2
- Provide test case classes for PHPUnit HOT 6
- Packagist is serving version 2.5.0 ? HOT 1
- has_filter/has_action return true instead of the hook priority HOT 7
- WP: adding mocks for some miscellaneous functions HOT 1
- Why expect function works unexpectedly? HOT 4
- Mocks for deep arguments in the function doesn't work HOT 5
- Testing w/o class or class instantiation within plugin HOT 2
- Adding Monkey\setUp() and tearDown() fails otherwise passing tests HOT 3
- has_filter doen't work with type hints with namespaces HOT 10
- Correct use of patchwork.json to redefine internal functions? HOT 4
- Docs site not up-to-date HOT 4
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
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.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from brainmonkey.