TDD with WordPress global functions and PHPUnit - wordpress

I'm trying to do tdd with my WordPress plugins. The problem is that using WP_UnitTestCase is way way to slow and despite the name provides integration tests rather than unit tests. So instead of using WP_UnitTestCase I have been working on creating truly isolated tests for my plugins but the problem is that I find myself using a lot of WordPress global functions such as wp_get_current_user() or wp_signon().
Currently I have a file of the functions I've used that are basically stubbed out.
What is the best way to go about mocking these functions? Ultimately I'd like to be able to mock these functions the same way as I would other methods with the ability to control their output and test that they're called. Is there a more OO way to set the current user or check for authentication that I'm missing?

You can create a class for invoking global WordPress functions. This can have a map of methods to global functions or even invoking whatever method is called that starts with wp_ using __call or any other way you come up with.
Then you would use this class from inside your plugin to call the functions. I suppose plugins are instantiated by WordPress so you won't be able to inject this class on production code. So you can make it externally settable to allow injecting a mock but if none is provided, use the real one.
Like this:
<?php
class Plugin
{
private $invoker;
public function getWpInvoker()
{
if (!isset($this->invoker)) {
$this->invoker = new WordPressGlobalFunctionsInvoker();
}
}
public function setWpInvoker(WordPressGlobalFunctionsInvoker $invoker)
{
$this->wp_invoker = $invoker;
}
public function foo()
{
$current_user = $this->getWpInvoker()->wp_get_current_user();
}
}
In the test you would mock the WordPressGlobalFunctionsInvoker class and inject the mock to the plugin so you take control over the functions being called.

Related

Differences between different methods of Symfony service collection

For those of you that are familiar with the building of the Symfony container, do you know what is the differences (if any) between
Tagged service Collector using a Compiler pass
Tagged service Collector using the supported shortcut
Service Locator especially, one that collects services by tags
Specifically, I am wondering about whether these methods differ on making these collected services available sooner or later in the container build process. Also I am wondering about the ‘laziness’ of any of them.
It can certainly be confusing when trying to understand the differences. Keep in mind that the latter two approaches are fairly new. The documentation has not quite caught up. You might actually consider making a new project and doing some experimenting.
Approach 1 is basically an "old school" style. You have:
class MyCollector {
private $handlers = [];
public function addHandler(MyHandler $hamdler) {
$handlers[] = $handler;
# compiler pass
$myCollectorDefinition->addMethodCall('addHandler', [new Reference($handlerServiceId)]);
So basically the container will instantiate MyCollector then explicitly call addHandler for each handler service. In doing so, the handler services will be instantiated unless you do some proxy stuff. So no lazy creation.
The second approach provides a somewhat similar capability but uses an iterable object instead of a plain php array:
class MyCollection {
public function __construct(iterable $handlers)
# services.yaml
App\MyCollection:
arguments:
- !tagged_iterator my.handler
One nice thing about this approach is that the iterable actually ends up connecting to the container via closures and will only instantiate individual handlers when they are actually accessed. So lazy handler creation. Also, there are some variations on how you can specify the key.
I might point out that typically you auto-tag your individual handlers with:
# services.yaml
services:
_instanceof:
App\MyHandlerInterface:
tags: ['my.handler']
So no compiler pass needed.
The third approach is basically the same as the second except that handler services can be accessed individually by an index. This is useful when you need one out of all the possible services. And of course the service selected is only created when you ask for it.
class MyCollection {
public function __construct(ServiceLocator $locator) {
$this->locator = $locator;
}
public function doSomething($handlerKey) {
/** #var MyHandlerInterface $handler */
$handler = $serviceLocator->get($handlerKey);
# services.yaml
App\MyCollection:
arguments: [!tagged_locator { tag: 'app.handler', index_by: 'key' }]
I should point out that in all these cases, the code does not actually know the class of your handler service. Hence the var comment to keep the IDE happy.
There is another approach which I like in which you make your own ServiceLocator and then specify the type of object being located. No need for a var comment. Something like:
class MyHandlerLocator extends ServiceLocator
{
public function get($id) : MyHandlerInterface
{
return parent::get($id);
}
}
The only way I have been able to get this approach to work is a compiler pass. I won't post the code here as it is somewhat outside the scope of the question. But in exchange for a few lines of pass code you get a nice clean custom locator which can also pick up handlers from other bundles.

What is the main advantage to use service in Symfony?

I'm a newbie on symfony, And I don't understand the advantage of use service instead of write the cose in Controller
For Example, I Have a service that Create Log, with a code like this:
$path = $root.'/../web';
$fs->touch($path.'/log.txt');
$this->file = $path.'/log.txt';
file_put_contents($this->file, $msg, FILE_APPEND | LOCK_EX);
I can put this login in service with DIC ($fs is FileSystem service), or I can Put this Login on my Controller.
Of course If i Need to log often I have to write the same code. The main advantage is decoupling?
Thanks a lot
Suppose you have a Bar class which uses BasicLogger.
You have a few ways to get access to this logger, lets start with the most simple option:
<?php
class Bar
{
public function bar()
{
$logger = new BasicLogger();
$logger->log("foo");
}
}
This is bad practice because we are mixing construction logic with application logic. It still works, but it has the following drawbacks:
It mixes responsibilities.
Bar becomes hard to test and cannot be tested without side effects.
We cannot dynamically change loggers (code is less reusable).
To solve these drawbacks, we can instead require our Logger class through the constructor.
Our code now looks like this:
class Bar
{
private $logger;
public function __construct(Logger $logger)
{
$this->logger = $logger;
}
public function bar()
{
$this->logger->log("foo");
}
}
Great, our class is no longer responsible for creating the logger, we can test our code without side effects (and make assertions against how the logger was used) and we can now use any logger we like.
So now we use our new class all over the application.
$logger = new Logger();
$bar = new Bar($logger);
Look familiar?
Again we are mixing construction logic with application logic, which we already know is bad.
Not only that, but something even worse is happening here, Code duplication.
Thats right. and every time we want to use our Bar class, the duplication gets worse.
The solution? Use the Service container
Registering your logger as a service would mean that all of your code that needs logging functionality is no longer dependent on your specific logger, responsibilities will not be mixed, code duplication will be reduced and your design will become more flexible.
The main goal and advantage of services is that keep reusable code and use a DRY approach.
Of course, there is a lot of other advantages that you discover progressively as you use them.
Services are accessible from whatever context of your application that can accesses the service container, not only controllers.
If without the service the few lines of code you give would be duplicated in several methods/contexts, you should keep your service.
Otherwise, delete it and do your logic in the specific method.
I think the better approach to use them is at your own feeling.
Don't try to create services in prevention, use them to solve a real need.
When you have a block of code that is duplicated, you should naturally avoid it by creating a service (or other AbstractController that your controllers can extend and inherit the code block) .
The goal is: Always keep a light code and avoid duplicates as possible.
For that, you can use the powerful services of Symfony, or just use the inheritance of classes and other POO principles.

Loading Fixtures for functional tests in Symfony 2: Call to undefined method MyControllerTest::loadFixtures())

I am trying to find the easy way to load my fixtures in Symfony 2.6 to run functional tests. This is a quite common question, and has been asked a few times, but the answers I have found so far do not quite reach my expectations:
Some rely on running the command line from inside the functional test.
Other run manually each one of the defined fixtures, and then take care of creating and deleting the database.
There is a lot of overhead in both cases (use statements and manual code), for a task that I believe is very standard.
On the other hand, these same posts recommend the LiipFunctionalTestBundle. Going for it, here is what I read in the installation instructions:
write fixture classes and call loadFixtures() method from the bundled
Test\WebTestCase class. Please note that loadFixtures() will delete the contents from the database before loading the fixtures."
So I tried...
namespace AppBundle\Test\Controller;
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
class MyControllerTest extends WebTestCase
{
public function setUp()
{
$classes = array(
'AppBundle\DataFixtures\LoadUserData',
);
$this->loadFixtures($classes);
}
...
}
With no luck:
Call to undefined method AppBundle\Tests\Controller\MyControllerTest::loadFixtures() in /gitrepos/myproject/src/AppBundle/Tests/Controller/MyControllerTest.php on line 15
a static call gives the same error...
self:loadFixtures($classes);
I really think I am missing something pretty obvious. Anyone can get me back on track ?
I can see you're using
Oro\Bundle\TestFrameworkBundle\Test\WebTestCase
as the base class while I think you should use
Liip\FunctionalTestBundle\Test\WebTestCase
to be able to call this method.

How to ensure that a method exists in the real object when mocked?

I would like my test to fail if I mock an interface using Mockery and use a shouldReceive with a non-existing method. Looking around didn't help.
For instance :
With an interface :
interface AInterface {
public function foo();
public function bar();
}
And a test case :
function testWhatever{
Mockery::mock('AInterface')->shouldReceive('bar');
$this->assertTrue(true);
}
The test will pass.
Now, refactoring time, bar method is not needed in one place (let's say it's needed on several places) and is suppressed from the interface definition but the test will still pass. I would like it to fail.
Is it possible to do such a thing using mockery (and to be able to do the same thing with a class instead of an interface) ?
Or does a workaround exist with some other tool or a testing methodology ?
Not sur if this can be understood as is, will try to make a clearer description of the issue if needed.
To ensure that Mockery doesn't allow you to mock methods that don't exist, put the following code in your PHPUnit bootstrap file (if you want this behavior for all tests):
\Mockery::getConfiguration()->allowMockingNonExistentMethods(false);
If you just want this behavior for a specific test case, put the code in the setUp() method for that test case.
Check this section of the Mockery manual on Github for more information.
If you want to make sure that the method is called only one time, you can use once().
Suppose that the class AImplementation, implements the interface AInterface, and you wanna tested that the method is called, an example could be:
Mockery::mock('AImplementation')->shouldReceive('bar')->once();
You can also use: zeroOrMoreTimes(), twice() or times(n), checkout the repo at github. Also, I recommend you this tutorial by Jeffrey W

Setting up functional Tests in Flex

I'm setting up a functional test suite for an application that loads an external configuration file. Right now, I'm using flexunit's addAsync function to load it and then again to test if the contents point to services that exist and can be accessed.
The trouble with this is that having this kind of two (or more) stage method means that I'm running all of my tests in the context of one test with dozens of asserts, which seems like a kind of degenerate way to use the framework, and makes bugs harder to find. Is there a way to have something like an asynchronous setup? Is there another testing framework that handles this better?
It is pretty easy, but took me 2 days to figure it out.
The solution:
First you need to create a static var somewhere.
public static var stage:Stage
There is a FlexUnitApplication.as created by the flexunit framework, and at the onCreationComplete() function, you can set the stage to the static reference created previously:
private function onCreationComplete():void
{
var testRunner:FlexUnitTestRunnerUIAS=new FlexUnitTestRunnerUIAS();
testRunner.portNumber=8765;
this.addChild(testRunner);
testStageRef.stage=stage //***this is what I've added
testRunner.runWithFlexUnit4Runner(currentRunTestSuite(), "testsuitename");
}
and when you would access the stage in the program, you should replace it to:
if(stage==null) stage=testStageRef.stage
Assuming you're using FlexUnit 4, addAsync can be called from a [BeforeClass] method:
public class TestFixture
{
[BeforeClass]
public static function fixtureSetup() : void
{
// This static method will be called once for all the tests
// You can also use addAsync in here if your setup is asynchronous
// Any shared state should be stored in static members
}
[Test]
public function particular_value_is_configured() : void
{
// Shared state can be accessed from any test
Assert.assertEquals(staticMember.particularValue, "value");
}
}
Having said that, testing code that accesses a file is really an integration test. I'm also hardly in a position to argue against using ASMock :)
Sounds like you need to remove the dependency of loading that external file. Pretty much all Aysnchronous tests can be removed through the use of a mocking frameworks. ASMock is an awesome choice for Flex. It will allow you to fake the URLoader object and return faked configurations to run your tests against. Mocking will help with you write much better unit tests as you can mock all dependencies synchronous or asynchronous.

Resources