Skip to content

Latest commit

 

History

History
216 lines (165 loc) · 5.81 KB

Test.md

File metadata and controls

216 lines (165 loc) · 5.81 KB

AspectMock\Test

AspectMock\Test class is a builder of test doubles. Any object can be enhanced and turned to a test double with the call to double method. Mocking abstract classes and interfaces is not supported at this time. This allows to redefine any method of object with your own, and adds mock verification methods.

Recommended Usage:

<?php
use AspectMock\Test as test;

public static double($classOrObject, array $params = Array ( ) )

test::double registers class or object to track its calls. In second argument you may pass values that mocked mathods should return.

Returns either of ClassProxy (when a string was passed) or InstanceProxy (when an object was passed). Proxies are used to verify method invocations, and some other useful things (check out the links above for more).

Examples:

<?php

# simple
$user = test::double(new User, ['getName' => 'davert']);
$user->getName() // => davert
$user->verifyInvoked('getName'); // => success
$user->getObject() // => returns instance of User, i.e. real, not proxified object

# with closure
$user = test::double(new User, ['getName' => function() { return $this->login; }]);
$user->login = 'davert';
$user->getName(); // => davert

# on a class
$ar = test::double('ActiveRecord', ['save' => null]);
$user = new User;
$user->name = 'davert';
$user->save(); // passes to ActiveRecord->save() and does not insert any SQL.
$ar->verifyInvoked('save'); // true

# on static method call
User::tableName(); // 'users'
$user = test::double('User', ['tableName' => 'fake_users']);
User::tableName(); // 'fake_users'
$user->verifyInvoked('tableName'); // success

# append declaration
$user = new User;
test::double($user, ['getName' => 'davert']);
test::double($user, ['getEmail' => 'davert@mail.ua']);
$user->getName(); // => 'davert'
$user->getEmail(); => 'davert@mail.ua'

# create an instance of mocked class
test::double('User')->construct(['name' => 'davert']); // via constructor
test::double('User')->make(); // without calling constructor

# stub for magic method
test::double('User', ['findByUsernameAndPasswordAndEmail' => false]);
User::findByUsernameAndPasswordAndEmail(); // null

# stub for method of parent class
# if User extends ActiveRecord
test::double('ActiveRecord', ['save' => false]);
$user = new User(['name' => 'davert']);
$user->save(); // false
  • api
  • param string|object $classOrObject
  • param array $params [ 'methodName' => 'returnValue' ]
  • throws Exception
  • return Verifier|Proxy\ClassProxy|Proxy\InstanceProxy

public static spec($classOrObject, array $params = Array ( ) )

If you follow TDD/BDD practices a test should be written before the class is defined. If you would call undefined class in a test, a fatal error will be triggered. Instead you can use test::spec method that will create a proxy for an undefined class.

<?php
$userClass = test::spec('User');
$userClass->defined(); // false

You can create instances of undefined classes and play with them:

<?php
$user = test::spec('User')->construct();
$user->setName('davert');
$user->setNumPosts(count($user->getPosts()));
$this->assertSame('davert', $user->getName()); // fail

The test will be executed normally and will fail at the first assertion.

test::spec()->construct creates an instance of AspectMock\Proxy\Anything which tries not to cause errors whatever you try to do with it.

<?php
$user = test::spec('Undefined')->construct();
$user->can()->be->called()->anything();
$user->can['be used as array'];
foreach ($user->names as $name) {
     $name->canBeIterated();
}

None of those calls will trigger an error in your test. Thus, you can write a valid test before the class is declared.

If class is already defined, test::spec will act as test::double.

  • api
  • param string|object $classOrObject
  • param array $params
  • return Verifier|Proxy\ClassProxy|Proxy\InstanceProxy

public static methods($classOrObject, array $only = Array ( ) )

Replaces all methods in a class with dummies, except those specified in the $only param.

<?php
$user = new User(['name' => 'jon']);
test::methods($user, ['getName']);
$user->setName('davert'); // not invoked
$user->getName(); // jon

You can create a dummy without a constructor with all methods disabled:

<?php
$user = test::double('User')->make();
test::methods($user, []);
  • api
  • param string|object $classOrObject
  • param string[] $only
  • return Verifier|Proxy\ClassProxy|Proxy\InstanceProxy
  • throws Exception

public static func($namespace, $functionName, $body)

Replaces function in provided namespace with user-defined function or value that function returns. Function is restored to original on cleanup.

<?php
namespace demo;
test::func('demo', 'date', 2004);
date('Y'); // 2004

test::func('demo', 'date', function($format) {
   if ($format == 'Y') {
     return 2004;
   } else {
     return \date($param);
   }
});

Mocked functions can be verified for calls:

<?php
namespace demo;
$func = test::func('demo', 'date', 2004);
date('Y'); // 2004
$func->verifyInvoked();
$func->verifyInvokedOnce(['Y']);
  • param mixed $body whatever a function might return or Callable substitute
  • return Proxy\FuncProxy

public static clean($classOrInstance = null)

Clears test doubles registry. Should be called between tests.

<?php
test::clean();

Also you can clean registry only for the specific class or object.

<?php
test::clean('User');
test::clean($user);
  • api
  • param string|object $classOrObject
  • return void

public static cleanInvocations()

Clears mock verifications but not stub definitions.

  • api
  • return void