AspectMock

Arba jei tau nepasisekė



Vaidas Mikalauskas


Jei tau pasisekė





 O jeigu ne


<?php

class Whatever {
    public static function registerNewUser(array $item) {
        $user = new User;
        $user->attributes = $item['user'];
        
        if (Users::model()->countByAttributes($item['email']) > 0) {
            throw new Exception('User with this email already exists');
        }

        if ($user->validate() && $user->save()) { 
            // password is hashed in `beforeSave()`
            Yii::app()->mailer->send($user->email
                new UserRegistrationNotification($user);
            );

            if ($user->isProUser()) {
                $manager = new UserSubscriptionManager();
                $manager->createSubscriptionPlan($user, $item['pro_details']);
            }

            if ($item['subscribe_to_newsletter']) {
                Newsletters::subscribeUserToAll($user);
            }

            return true;
        }
        return false;
    }
}

Dėl ko tau nepasisekė




  • static function()
  • new UserSubscriptionManager();
  • Yii::app()
  • User::model()
  • Newsletters::subscribeUserToAll();
  • depends on mailer, db, config, service managers, etc...








Nu neina pratestint!







AspectMock



Static functions:

<?php
function testStaticMethod() {
    test::double('App\Users', ['tableName' => 'test_table']);

    $this->assertEquals('test_table', \App\Users::tableName());
}

Global function overrides:

<?php
public function testGlobalOverrides()
{
    test::double('App\Users', ['getFullName' => 'Peter']);
    
    $user = new \App\Users;
    $this->assertEquals('Peter', $user->getFullName());
}

Invocation testing

<?php
public function testStatic()
{
    $double = test::double('App\Users', ['tableName' => 'test_table']);
    $this->assertEquals('test_table', \App\Users::tableName());
    $double->verifyInvoked('tableName');
    $double->verifyNeverInvoked('save');
}

Install

{
    "require": {
        "codeception/aspect-mock": "0.4.2"
    }
}

Initialize

<?php
include __DIR__.'/../vendor/autoload.php'; // composer autoload

$kernel = \AspectMock\Kernel::getInstance();
$kernel->init(['includePaths' => [__DIR__.'/../src']]);

Start using

<?php
use AspectMock\Test as Test;

Test::double('OfClass', ['methodName'=>'returnValue'])



 NOT BAD,
but how does it work?

Aspect-oriented programming

Code parsing





<?php
require 'myfile.php';


<?php
require 'php://read=go.source.transforming.loader/resource=myfile.php';

Behind the scenes


<?php
class User {
    
    function setName($name)
    {
        $this->name = $name;
    }    

}
<?php
class User {
    
    function setName($name)
    { if (($__am_res = __amock_before($this, __CLASS__, __FUNCTION__, array($name.........
        $this->name = $name;
    }

}

Tips & Tricks





  • Always test::clean()
  • All best TDD practices still apply
  • God classes are still evil
  • If possible, limit AspectMock to "src/"

Should I use it?






NO

If you can

FAQ




Does AspectMock slows down tests?
YES

Ok, but can it mock ........ class/function/whatever?
YES

Does it require any special configuration or extensions?
NO

Thank you








Questions?
Made with Slides.com