Posts tagged 'testing'

Mockery return values based on arguments

published on December 12, 2017.

Sometimes when working with Mockery mock objects, we want to tell a mocked method to return different values for different arguments. It is a rare occasion when I need this feature, but every time I need it, I’m happy it’s there.

The feature that allows us to return different values based on arguments is the andReturnUsing Mockery method, which takes a closure as an argument:

example.php

$dependencyMock = \Mockery::mock('SomeDependency');
$dependencyMock->shouldReceive('callDependency')
    ->andReturnUsing(function ($argument) {
        if ($argument <= 10) {
            return 'low';
        }

        return 'high';
    });

$dependencyMock->callDependency(10); // 'low'
$dependencyMock->callDependency(11); // 'high'

Any number of times we call our callDependency method on our mock object with a number 10 or less, it will return 'low', otherwise it will return 'high'.

Not much of an example, so let’s take a look at one a bit closer to a real world scenario.

Say we’re using Doctrine’s entity manager to get repositories for our entities in a service class:

src/ArticleService.php

<?php

class ArticleService
{
    public function __construct(EntityManager $em)
    {
        $this->articleRepo = $em->getRepository(Entity\Article::class);
        $this->authorRepo = $em->getRepository(Entity\Author::class);
    }
}

Not the best of the codes, but we’ll manage. The entity manager receives two calls to the getRepository method, once for the Article entity, once for the Author entity.

In a test case we could then set up the mocks like so:

tests/ArticleServiceTest.php

<?php

class ArticleServiceTest extends MockeryTestCase
{
    public function setup()
    {
        $this->authorRepositoryMock = \Mockery::mock(AuthorRepository::class);
        $this->articleRepositoryMock = \Mockery::mock(ArticleRepository::class);
        $this->entityManagerMock = \Mockery::mock(EntityManager::class);
    }

    public function testArticleService()
    {
        $repositoryMap = [
            'Entity\Author' => $this->authorRepositoryMock,
            'Entity\Article' => $this->articleRepositoryMock,
        ];
        $this->entityManagerMock->shouldReceive('getRepository')
            ->andReturnUsing(function($argument) use ($repositoryMap) {
                return $repositoryMap[$argument];
            });

        $articleService = new ArticleService($this->entityManagerMock);
    }
}

In the setup method we create the three mock objects that we need and then in the test method we create a $repositoryMap to help us map entities to repositories. The repository map could have been created in the andReturnUsing closure as well.

Now when we instantiate the ArticleService with the mocked entity manager, that mocked entity manager will receive two calls to the getRepository method in the ArticleServices constructor, and it will use the closure defined in andReturnUsing to return the correct repository mock objects.

More than one way to do it

Of course there is another way to achieve the same thing and that’s by using andReturn for the return value expectations, but it’s a bit more to write:

tests/ArticleServiceTest.php

<?php
    public function testArticleService()
    {
        $this->entityManagerMock->shouldReceive('getRepository')
            ->with('Entity\Author')
            ->andReturn($this->authorRepositoryMock);
        $this->entityManagerMock->shouldReceive('getRepository')
            ->with('Entity\Article')
            ->andReturn($this->articleRepositoryMock);

        $articleService = new ArticleService($this->entityManagerMock);
    }

It does the same thing as the previous thing. We might even argue that this second example is even clearer than the first example, sure, for a relatively small argument “map”. But if we need to handle a case with more than just two possible arguments, andReturnUsing can help us in those cases.

Happy hackin’!

P.S.: The proper way to do this actually would be to refactor that ArticleService to not get the two repositories from the entity manager, but to inject them directly instead.

Complex argument matching in Mockery

published on May 08, 2017.

This past weekend I did some issue maintenance and bug triage on Mockery. One thing I noticed going through all these issues, is that people were surprised when learning about the \Mockery::on() argument matcher. I know Mockery’s documentation isn’t the best documentation out there, but this still is a documented feature.

First of all, Mockery supports validating arguments we pass when calling methods on a mock object. This helps us expect a method call with one (set of) argument, but not with an other. For example:

<?php
$mock = \Mockery::mock('AClass');

$mock->shouldReceive('doSomething')
    ->with('A string')
    ->once();

$mock->shouldReceive('doSomething')
    ->with(42)
    ->never();

This will tell Mockery that the doSomething method should receive a call with A string as an argument, once, but never with the number 42 as an argument.

Nice and simple.

But things are not always so simple. Sometimes they are more complicated and complex.

When we need to do a more complex argument matching for an expected method call, the \Mockery::on() matcher comes in really handy. It accepts a closure as an argument and that closure in turn receives the argument passed in to the method, when called. If the closure returns true, Mockery will consider that the argument has passed the expectation. If the closure returns false, or a “falsey” value, the expectation will not pass.

I have used the \Mockery::on() matcher in various scenarios — validating an array argument based on multiple keys and values, complex string matching… and every time it was invaluable. Though, now that I think back, the older the codebase, the higher the usage frequency was. Oh, well.

Say, for example, we have the following code. It doesn’t do much; publishes a post by setting the published flag in the database to 1 and sets the published_at to the current date and time:

<?php
namespace Service;
class Post
{
    public function __construct($model)
    {
        $this->model = $model;
    }

    public function publishPost($id)
    {
        $saveData = [
            'post_id' => $id,
            'published' => 1,
            'published_at' => gmdate('Y-m-d H:i:s'),
        ];
        $this->model->save($saveData);
    }
}

In a test we would mock the model and set some expectations on the call of the save() method:

<?php
$postId = 42;

$modelMock = \Mockery::mock('Model');
$modelMock->shouldReceive('save')
    ->once()
    ->with(\Mockery::on(function ($argument) use ($postId) {
        $postIdIsSet = isset($argument['post_id']) && $argument['post_id'] === $postId;
        $publishedFlagIsSet = isset($argument['published']) && $argument['published'] === 1;
        $publishedAtIsSet = isset($argument['published_at']);

        return $postIdIsSet && $publishedFlagIsSet && $publishedAtIsSet;
    }));

$service = new \Service\Post($modelMock);
$service->publishPost($postId);

\Mockery::close();

The important part of the example is inside the closure we pass to the \Mockery::on() matcher. The $argument is actually the $saveData argument the save() method gets when it is called. We check for a couple of things in this argument:

  • the post ID is set, and is same as the post ID we passed in to the publishPost() method,
  • the published flag is set, and is 1, and
  • the published_at key is present.

If any of these requirements is not satisfied, the closure will return false, the method call expectation will not be met, and Mockery will throw a NoMatchingExpectationException.

Happy hackin’!

PHP traits to create test doubles

published on April 04, 2017.

Keeping your application or library code well organized, easy to follow, and read is important. Your test code should not be exempt from those rules, you should follow good testing conventions.

One part of my tests that I feel like that are out of control are the test doubles. Dummies, fakes, mocks… Seems like they are everywhere and that I keep writing the same ones over and over again.

I do follow some good practices on how to reduce code duplication in my tests, but these mocks…

Ugh.

Test doubles are everywhere

Lets look at a couple of example test cases:

tests/App/UnitTest/Transaction/TransactionTest.php

<?php declare(strict_types=1);
namespace App\UnitTest\Transaction;

use PHPUnit\Framework\TestCase;
use App\Account\Account;
use App\Account\AccountType;
use App\Transaction\Transaction;

class TransactionTest extends TestCase
{
    protected $asset;
    protected $expense;

    public function setup()
    {
        $this->asset = new Account(new AccountType('asset'), 'Cash');
        $this->expense = new Account(new AccountType('expense'), 'Groceries');
    }

    public function testTransactionCanBeExecutedBetweenAssetAndExpenseAccounts()
    {
        $transaction = new Transaction($this->asset, $this->expense, '5', 'EUR');

        $result = $transaction->execute();

        self::assertTrue($result);
    }

    public function testTransactionCannotBeExecutedBetweenExpenseAndAssetAccounts()
    {
        $transaction = new Transaction($this->expense, $this->asset, '5', 'EUR');

        $result = $transaction->execute();

        self::assertFalse($result);
    }
}

It’s not so bad, right? We create a couple of account types, so we can create a couple of account objects which are then used to test can a transaction be executed or not.

And then we need to test the persistence of the transaction in another test case. Again we create a couple of account types, accounts, create a transaction…

And then we need to test the TransactionExecuted event. Account types, accounts, transaction…

Over and over again.

Traits to the rescue

What if we move the creation of those test doubles to traits?

A trait for creating account types:

tests/Traits/AccountTypeTrait.php

<?php declare(strict_types=1);
namespace Traits;

use App\Account\AccountType;

trait AccountTypeTrait
{
    public function fakeAssetAccountType() : AccountType
    {
        return new AccountType('asset');
    }

    public function fakeExpenseAccountType() : AccountType
    {
        return new AccountType('expense');
    }
}

and a trait for creating accounts:

tests/Traits/AccountTrait.php

<?php declare(strict_types=1);
namespace Traits;

use App\Account\Account;
use Traits\AccountTypeTrait;

trait AccountTrait
{
    use AccountTypeTrait;

    public function fakeAssetAccount() : Account
    {
        return new Account($this->fakeAssetAccountType());
    }

    public function fakeExpenseAccount() : Account
    {
        return new Account($this->fakeExpenseAccountType());
    }
}

The example test case from the beginning now becomes a little bit more clear, hopefully:

tests/App/UnitTest/Transaction/TransactionTest.php

<?php declare(strict_types=1);
namespace App\UnitTest\Transaction;

use PHPUnit\Framework\TestCase;
use App\Transaction\Transaction;
use Traits\AccountTrait;

class TransactionTest extends TestCase
{
    use AccountTrait;

    public function testTransactionCanBeExecutedBetweenAssetAndExpenseAccounts()
    {
        $transaction = new Transaction($this->fakeAssetAccount(), $this->fakeExpenseAccount(), '5', 'EUR');

        $result = $transaction->execute();

        self::assertTrue($result);
    }

    public function testTransactionCannotBeExecutedBetweenExpenseAndAssetAccounts()
    {
        $transaction = new Transaction($this->fakeExpenseAccount(), $this->fakeAssetAccount(), '5', 'EUR');

        $result = $transaction->execute();

        self::assertFalse($result);
    }
}

A trait for every test double, clearly named as to what they create. fakeAssetAccount, mockTransactionRepository. Each test double can now be reused more easily across different test cases, if for some reason they need to be changed, we change them only in one place.

Just need to be disciplined on the naming of the traits and the methods they provide.

Currently I see no pitfalls with this approach, but time will tell is this a good idea or not.

Happy hackin’!

Mocking hard dependencies with Mockery

published on December 23, 2014.
Heads-up! You're reading an old post and the information in it is quite probably outdated.

One problem with unit testing legacy applications is that the code has new statements all over the place, instantiating new objects in a way that doesn’t really makes it easier to test the code.

Of course, the easy answer to this is “Just refactor your application!”, but that’s almost always easier said than done.

If refactoring is an option, do it. If not, one option is to use Mockery to mock the hard dependencies.

One prerequisite to make this work is that the code we are trying to test uses autoloading.

Let’s take the following code for an example:

<?php
namespace App;
class Service
{
    function callExternalService($param)
    {
        $externalService = new Service\External();
        $externalService->sendSomething($param);
        return $externalService->getSomething();
    }
}

The way we can test this without doing any changes to the code itself is by creating instance mocks by using the overload prefix.

<?php
namespace AppTest;
use Mockery as m;
class ServiceTest extends \PHPUnit_Framework_TestCase {
    public function testCallingExternalService()
    {
        $param = 'Testing';

        $externalMock = m::mock('overload:App\Service\External');
        $externalMock->shouldReceive('sendSomething')
            ->once()
            ->with($param);
        $externalMock->shouldReceive('getSomething')
            ->once()
            ->andReturn('Tested!');

        $service = new \App\Service();

        $result = $service->callExternalService($param);

        $this->assertSame('Tested!', $result);
    }
}

If we run this test now, it should pass. Mockery does it’s job and our App\Service will use the mocked external service instead of the real one.

The problem whit this is when we want to, for example, test the App\Service\External itself, or if we use that class somewhere else in our tests.

When Mockery overloads a class, because of how PHP works with files, that overloaded class file must not be included otherwise Mockery will throw a “class already exists” exception. This is where autoloading kicks in and makes our job a lot easier.

To make this possible, we’ll tell PHPUnit to run the tests that have overloaded classes in separate processes and to not preserve global state. That way we’ll avoid having the overloaded class included more than once. Of course this has it’s downsides as these tests will run slower.

Our test example from above now becomes:

<?php
namespace AppTest;
use Mockery as m;
/**
 * @runTestsInSeparateProcesses
 * @preserveGlobalState disabled
 */
class ServiceTest extends \PHPUnit_Framework_TestCase {
    public function testCallingExternalService()
    {
        $param = 'Testing';

        $externalMock = m::mock('overload:App\Service\External');
        $externalMock->shouldReceive('sendSomething')
            ->once()
            ->with($param);
        $externalMock->shouldReceive('getSomething')
            ->once()
            ->andReturn('Tested!');

        $service = new \App\Service();

        $result = $service->callExternalService($param);

        $this->assertSame('Tested!', $result);
    }
}

And that should be pretty much it. If nothing else, it should make parts of old code easier to test.

For anyone interested, I put the example code up on Github.

Frontend testing with phantomjs and casperjs

published on January 29, 2013.
Heads-up! You're reading an old post and the information in it is quite probably outdated.

I am not usually fond of doing much frontend stuff, but I do like to dable in some javascript from time to time. Nothing fancy, no node.js, coffeescript and the likes for me. I still feel like making applications on the server side, and have the client just show things to the user. If needed some 3rd party javascript library or framework to make my life easier, and that’s about it.

For a while I was reluctant on writing any frontend tests, integration tests, or whatever you want to call them, because, y’know, refresh-click-click-click and the testing is done. Easy. Except when it’s not. From time to time some piece of user interface gets wild on javascript and it turns out after a couple of weeks, half a dozen of bugs reported, and hundreds of refreshes and thousands of clicks, that whole thing becomes tiresome. Thus, I decided to dabble my toes deeper in the waters of the javascript world and try writing some tests for all this.

What I found first is that there’s a lot of testing libraries out there for javascript. Won’t even try listing them all. When I set out for the hunt I knew what I wanted and needed. I wanted a tool that will help me automate all my refreshclicks, or at least to some extent. Tell the tool through my tests: “go to that page, check what and how is rendered, do some things with the UI, test again”. The less dependencies it has on other things, the better. I asked around among people who are bit more fluent in javascript than I am, what are they using and what would they recommend. Not too much to my surprise, everyone recommended a different thing, whatever fits their problem. So I ended up picking the tools that fit my problem.

The tools chosen

The first tool I picked was phantomjs. It’s a “headless WebKit with JavaScript API. It has fast and native support for various web standards: DOM handling, CSS selector, JSON, Canvas, and SVG.” (shamelessly copy-pasted from their website). When installing it either download a binary from their website, or compile the source on your own. If you’re on Ubuntu, do not install it via apt-get. It installs some very old version, 1.4 I think, and phantomjs will just scream at you something about some X servers. The binaries are pre-built for any and all systems, so just use them (not that I tried all of them, but I trust they all work).

To cut the story short, writing tests with just phantomjs is difficult. If at all possible. Because hey! It’s not a testing library. I think. This part is a bit blurry for me.

Enter casperjs! These two together look like a perfect match for doing automated, frontend tests full of javascript.

Even though last week on Friday I was being a bit frustrated and a bit more of a dick and said bad things about casperjs over twitter which I shouldn’t have. Sorry. Broken things on a Friday at 5PM can do that to a man.

Examples!

That’s why you’re here, to see some examples. And this example, which, btw, is on Github here, will have a simple login page with a form and a logged in page with some UI elements that you can click around and do stuff! And we’re going to test all that with phatnomjs and casperjs. Just like real life. Cookies included.

When writing tests with phantomjs and casperjs, all one need to do is think in steps. Same simple steps like in the refreshclick procedure. First, open page. Make sure we are on the correct page. Make sure all the elements are there. Click something. Make sure that thing is clicked. Fill in a field. Make sure the field is filled. And so on.

Let’s have a look at the first part of the tests.js file:

casper.start('http://localhost/frontend-testing', function () {
    this.test.assertUrlMatch(/login.php$/, 'Redirected to login page');
    this.test.assertExist("#login_form", 'Login form exists');
    this.fill('#login_form', {
        'email': 'email@example.com'
    }, false); // false means don't autosubmit the form
    this.test.assertField('email', 'email@example.com');
});
casper.thenClick('#login', function () {
    this.test.assertUrlMatch(/index.php$/, 'Redirected to index page after login');
});

The tests are surprisingly self-explanatory: start by opening up the home page. Assert that we are (redirected to) on the login page and that the login form exists. Then fill the email field of the login form with a given value. Assert that the field was indeed filled with that value. Once that’s done, then click on the login button, and assert that we end up on the index page.

Easy!

And practically that goes on in the entire test. Start, assert, then do this, assert, then do that, assert, done.

Testing ajax calls isn’t difficult either:

casper.thenClick('#do_ajax', function () {
    this.waitForResource('http://localhost/frontend-testing/ajax.php');
});
casper.then(function () {
    // Sometimes we need to wait a bit more for ajax requests ...
    this.wait(50);
});
casper.then(function () {
    this.test.assertTextExist('Just some ajax response.', 'Ajax request was made');
});

Do some action that triggers an ajax request, wait for that ajax request to finish and assert that something was done with the response from that ajax call. Of course, in real life examples you will have a bit more complicated setup, but hey… As for faking ajax requests I hear that can be done with this cool sinonjs library, but I haven’t managed to get that working, yet. Mostly because I didn’t need to fake any ajax calls.

The most voodoo-like thing in these tests is probably the evaluate() part. I don’t think I really know what that it is, but what I think it is, that, whenever you want to do something in the actual webpage, but from within the tests, you use evaluate().

For example, I had to use evaluate() to determine is the checkbox checked or not:

casper.thenClick('#enable_ajax', function () {
    // I could swear I had this one working
    // this.test.assertEquals(this.getElementAttribute('#enable_ajax', 'checked'), 'checked', 'Checkbox is checked');
    this.test.assertTrue(this.evaluate(function () { 
        return document.getElementById("enable_ajax").checked;
    }), 'Checkbox is checked');
});

Not sure how, but the this.getElementAttribute() way does actually work in my other tests. Honest. Not sure why it didn’t work in this example. Maybe some other factors not present here, affected my other tests? I don’t know.

Helpful bits

What I found extremely helpful while writing the tests is the this.debugHtml() and this.debugPage() casper functions. The former will dump the entire HTML to the terminal, and the latter will dump just the text of the entire page. Can be useful to figure out what’s going on.

The other helpful debugging function I used a lot is this.getElementAttribute(<selector>). It retrieves a bunch of helpful information on an element, which you can then dump to the terminal, to further figure out things:

casper.then(function () {
    require('utils').dump(this.getElementAttribute('#enable_ajax'));
});

Will result in an output like this:

{
    "attributes": {
        "id": "enable_ajax",
        "name": "enable_ajax",
        "type": "checkbox"
    },
    "height": 13,
    "html": "",
    "nodeName": "input",
    "tag": "<input type=\"checkbox\" name=\"enable_ajax\" id=\"enable_ajax\">",
    "text": "",
    "visible": true,
    "width": 13,
    "x": 12,
    "y": 58
}

I mean, it even gives the positions of the checkbox on the page! Super helpful.

casperjs supports CSS3 selectors and, which gives me much joy, XPath. Makes getting those pesky little elements covered in layers of divs and tables a walk in the park.

One thing though: you can’t do things like selecting multiple elements at once and then .each()‘em or something like that. You have to select elements one by one and do assertions on each of them. Even if the selector matches multiple elements, it will just return the first element, so you’ll probably end up using lots of :nth-child(n) selectors. But that’s what copy-paste was invented for.

That’s about it, I guess. Of course, there’s much more to both phantomjs and casperjs, but I found the documentations well written, so I believe it’s fairly easy to tackle even the testing of more complicated web pages with these libraries.

Happy testing!

Robert Basic

Robert Basic

Software engineer, consultant, open source contributor.

Let's work together!

If you require outsourcing or consulting help on your projects, I'm available!

Robert Basic © 2008 — 2018
Get the feed