AspectMock là gì? Tại sao dùng AspectMock với Codeception

1. AspectMock là gì?

AspectMock là PHP mocking framework đã được tối ưu và dễ sử dụng so với Mock trong PHP Unit và Mockery. Nó được tạo ra như một phần mở rông trong việc sử dụng Codeception hoặc PHP Unit để test. Vì quá thuận tiện và ngắn gọn nên trong lúc viết test code, mình vẫn thấy khó khăn trong việc custom lại. Cái này thì tùy mỗi người dùng sẽ có cảm nhận riêng, mình vẫn đánh giá cao framework này.

2. Tại sao dùng AspectMock với Codeception?

Để biết câu trả lời hãy xem ưu điểm khi sử dụng AspectMock so với Mock/Stub trong PHP Unit:

  • Nhân bản được các static methods
  • Nhân bản các class methods called anywhere
  • Cách viết dễ dàng, dễ nhớ và ngắn gọn vô cùng so với PHP Unit.
  • Do kế thừa từ PHP Unit nên bạn có thể dùng PHP Unit tùy ý trong AspectMock nếu cần.

3. Cài đặt

Tham khảo tại https://github.com/Codeception/AspectMock

php composer.phar update

composer require codeception/aspect-mock --dev
<?php
    use AspectMock\Test as aspectMock;
    class ClassNameTest extends \PHPUnit_Framework_TestCase
?>

4. Sử dụng

4.1. Mock / Stub (Object / Function)

4.1.1. Object and some function in it

Mock Class and fake some method in it using aspectMock

aspectMock::double function
$mock = aspectMock::double('\Name\Space\MockClassName', array(
    'methodNeedMock' => 'fake return value',
    'methodNeedMock2' => array('different fake return value'),
));

Stub Class and fake some method in it using aspectMock (replace double for Stub)

aspectMock::spec function 
$mock = aspectMock::spec('\Name\Space\MockClassName', array(
    'methodNeedMock' => 'fake return value',
    'methodNeedMock2' => array('different fake return value'),
));

Another way, using PhpUnit (not recommended in this document)

PhpUnit getMockBuilder 
$resultSet = $this->getMockBuilder('ResultSet')
    ->setMethods(['current', 'as_array'])        // Add list function for use
    ->getMock();
$resultSet->method('as_array')->willReturn(array('Fake return array'));

Get Class instance with call / not call constructor

PhpUnit getMockBuilder 
//  Simple
$obj = $mock->construct();
 
//  With construct params
$obj = $mock->construct($param1,$param2);
 
//  Without calling constructor
$obj = $mock->make();

4.1.2. Built-in PHP function

public static func($namespace, $functionName, $body)
aspectMock::func('\Name\Space', 'date', function($format) {
   if ($format == 'Y') {
     return 2004;
   } else {
     return \date($format);
   }
}

4.1.3. Test private / protect function

$reflection        = new \ReflectionClass('MyClassName');
$reflection_method = $reflection->getMethod('MyMethodName');
$reflection_method->setAccessible(true);

4.2. Verify Invoked Function

// Verify invoked at least once
$obj->verifyInvoked('methodName');
 
 
// Invoked exactly with $param1 and $param2 values
$obj->verifyInvoked('methodName',[$param1,$param2]);
 
 
// Inovked that method was called exactly $times times.
 $obj->verifyInvokedMultipleTimes('methodName', $times, $params = array());
 
 
// Method never invoked
$obj->verifyNeverInvoked('methodName', $params = array());
 
 
// Get list of call method with all of params for each call
$user = aspectMock::double('UserModel');
$user->someMethod('arg1', 'arg2');
$user->someMethod('arg3', 'arg42');
$user->getCallsForMethod('someMethod') // Will return [ ['arg1', 'arg2'], ['arg3', 'arg4']]

 

4.3. Annotations

4.3.1. @dataProvider

Test function with params in data set

Examplie 
/**
 * @dataProvider additionProvider
 */
public function testAdd($a, $b, $expected)
{
    $this->assertEquals($expected, $a + $b);
}
 
public function additionProvider()
{
    return [
        [0, 0, 0],
        [0, 1, 1],
        [1, 0, 1],
        [1, 1, 3]
    ];
}

4.3.2. @require

Possible @requires usages

Type
Possible Values
Examples
Another example
PHPAny PHP version identifier@requires PHP 5.3.3@requires PHP 7.1-dev
PHPUnitAny PHPUnit version identifier@requires PHPUnit 3.6.3@requires PHPUnit 4.6
OSA regexp matching PHP_OS@requires OS Linux@requires OS WIN32|WINNT
functionAny valid parameter to function_exists@requires function imap_open@requires function ReflectionMethod::setAccessible
extensionAny extension name along with an optional version identifier@requires extension mysqli@requires extension redis 2.2.0

4.3.3. @codeCoverageIgnore

exclude lines of code from the coverage analysis

4.4. Assert

Show more here

  • assertTrue()
  • assertFasle()
  • assertEquals($expect,$actual)
  • assertEmpty()
  • assertNull()
  • assertCount()
  • assertContain()

 

Sliding Sidebar

About Me

About Me

Hello, my name is Dũng (Johnny). Welcome to my blog.

As I’m a developer, I write about topics related to the field of programming, mainly from a technical point of view. On this blog you’ll find posts which encourage discussion, information about development trends, case studies, reviews, tutorials, tips on how to improve your effectiveness, and anything else that might be fascinating to people from the IT industry.
I love PHP, NodeJS, Java,... and Fullstack.