phpunit with mocking and crawling

Post on 13-Apr-2017

570 Views

Category:

Technology

4 Downloads

Preview:

Click to see full reader

TRANSCRIPT

1

PHPUNITMocking and Crawling

2

Unit Test là gì• Unit test là việc kiểm tra để đảm bảo rằng các đoạn chức

năng chạy đúng

• Lợi ích: mỗi khi thay đổi code chỉ cần run test là có thể kiểm tra lại xem có bị degrade phần nào ko

• Tuy nhiên: tốn effort để làm, nhàm chán

• Nên hay không?

=> Có...nếu làm tốt

3

PHP UNIT• Unit testing framework dành cho PHP

• Tạo bởi: Sebastian Bergmann

• Phiên bản mới nhất 5.1

• Github: https://github.com/sebastianbergmann/phpunit

• Cài đặt: composer global require "phpunit/phpunit=5.1.*"

4

Ví dụpublic function testAdd($a, $b, $expected) { $this->assertEquals($expected, $a + $b); }

$this->withSession([‘post_confirm' => 1]) ->visit(action(‘PostController@getConfirm')) ->see(‘Confirmed Post!’) ->see($input['email']);

$user = factory(\App\Models\User::class)->create(['nick_name' => 'Shanelle Marks']);$this->be($user);$this->visit(action('LoginController@getIndex')) ->seePageIs(action('TopPageController@getIndex'));

$this->post(action('LoginController@postChangePassword'), $input) ->seeInDatabase('users', [ 'password' => $hashPassword, ])

public function testGetIndexWithoutPermission(){ $administrator = factory(\App\Models\Administrator::class)->create(['role' => 3]); $this->actingAsAdmin($administrator) ->get(action('Admin\AdminArticleController@getIndex')) ->assertResponseStatus(403);}

5

Dom Crawler – hình dung

6

DOM Crawler• tự động phân tích dữ liệu từ nguồn nội dung sau đó bóc tách

những thông tin cần thiết theo tiêu chí mà nó được lập trình viên hệ thống thiết lập.

• Google Bot

• Ứng dụng với PHPUnit?

=> Phân tích và test HTML trả về• Symfony DomCrawler Component

=> http://symfony.com/doc/current/components/dom_crawler.html

7

Symfony DomCrawler$crawler = new Crawler($html);

foreach ($crawler as $domElement) { var_dump($domElement->nodeName);}

Khởi tạo

Duyệt bằng Xpath$crawler = $crawler->filterXPath('//div/p[@class="framgia"]/a');

Duyệt bằng jQuery-like selectors$crawler = $crawler->filter('div > p[class="framgia"] > a');

Node Traversing$crawler->filter('body > p')->eq(0);$crawler->filter('body > p')->first();$crawler->filter('body > p')->last();$crawler->filter('body > p')->siblings();$crawler->filter('body > p')->nextAll();$crawler->filter('body > p')->previousAll();$crawler->filter('body > p')->children();$crawler->filter('body > p')->parents();

Accessing Node Values$crawler->filter('body > p')->nodeName();$crawler->filter('body > p')->text();$crawler->filter('body > p')->html();$crawler->filter('body > p')->attr('name');

8

Crawler Example• Test image url

• Test hide div

• Test paging

$this->actingAs($user)->visit(action('RecordController@getDetail', $dietRecord->id)) ->crawler->filter('img.posted-photo') ->each(function (Crawler $node, $i) use($img) { $this->assertEquals($node->attr('src'), image_url($img->img_url)); });

$editButton = $this->actingAs($user2)->visit(route('mypage', $user->id)) ->see(trans('mypage/labels.edit_method_in_practice')) ->crawler->filter('#myPracticeListEdit');$this->assertContains('hide', $editButton->attr('class'));

$pagination = $this->actingAsAdmin($administrator) ->visit(action('Admin\AdminMemberController@getIndex', $input)) ->crawler->filter('ul.pagination');

$this->assertEquals(0, $pagination->count());

9

Mocking – hình dung

10

Mocking – tại sao cần• Test ko phụ thuộc các phần khác (Ex: Controller ->

Service -> DAO), hay người khác (module chưa làm xong)

• Có cần test Data access, Cache, Framework?

• Tạo ra 1 object chứa các thuộc tính, phương thức trả về kết quả theo ý muốn phục vụ việc test

• Mock object Framework hoạt động thông qua proxy, cần Dependency Injection

11

Lợi ích của Mock Object• Isolate - cô lập• Non-deterministic results – tránh những kết quả ko đoán

định được• Different states – tránh khác biệt trạng thái(3rd party API)• Speed – nhanh (CI run test each commit, DB so slow)• No existent objects – không phụ thuộc object khác• Mock Objects are simply an object that mimics the real

object. You can tell the mock object what methods you want to call, in what order and what parameters it should accept. You can then tell the Mock Object what you expect it to return.

12

Ví dụinterface ExtensionManagerInterface{ function checkExtension($fileName);}

class ExtensionManager implements ExtensionManagerInterface{ public function checkExtension($fileName) { //Some complex business logic might goes here. May be DB operation or file system handling return false; }}

class FileChecker{ private $objManager = null; //Default constructor function __construct() { $this->objManager = new ExtensionManager(); }

//Parameterized constructor function __construct(ExtensionManagerInterface $tmpManager) { $this->objManager = $tmpManager; }

public function checkFile($fileName) { //Check file size, file name length,... return $this->objManager->checkExtension($fileName); }}

13

Test//Stub implementation to bypass actual Extension manager class.class StubExtensionManager implements ExtensionManagerInterface{ public function checkExtension($fileName) { return true; }}

public function testCheckFileFunction(){ $stubExtensionManagerObject = new StubExtensionManager; $fileCheckerObject = new FileChecker($stubExtensionManagerObject); $this->assertTrue($fileCheckerObject->checkFile('framgia.com'));}

14

Mockery• Mockery is a powerful Mock Object framework for PHP

testing• Mockery offers a more natural language• Mockery does not override or conflict with PHPUnit's

built-in mocking functions; in fact, you can use them both at the same time• Install easy via composer • Mock a class - setUp()

• Close after used – teardown()

"mockery/mockery": "0.9.*",

$userServiceMock = Mockery::mock(\App\Services\UserService::class);

$this->app->instance(\App\Services\UserService::class, $userServiceMock);

Mockery::close();

15

Mockery usage• shouldReceive

• with/andReturn

• Get mock

public function testIndex(){ $this->mock->shouldReceive('all')->once();}

Cache::shouldReceive('get') ->times(3) ->with('key') ->andReturn('value');

->with(\Mockery::any()) OR ->with(anything())->with(\Mockery::on(closure))->with('/^foo/') OR ->with(matchesPattern('/^foo/'))->with(\Mockery::mustBe(2)) OR ->with(identicalTo(2))->with(\Mockery::not(2)) OR ->with(not(2))->with(\Mockery::anyOf(1, 2)) OR with(anyOf(1,2))->with(\Mockery::subset(array(0 => 'foo')))->with(\Mockery::contains(value1, value2))->with(\Mockery::hasKey(key))

->shouldReceive(method1, method2, ...)->andThrow(Exception)->andThrow(exception_name, message)->zeroOrMoreTimes()->atLeast()->times(3)->atMost()->times(3)->between(min, max)

$mock = \Mockery::mock('foo')->shouldReceive('foo')->andReturn(1)->getMock();

16

Mockery usage• Partial Mocks

$this->mock = Mockery::mock('MyClass[save, send]');

$this->mock = Mockery::mock('MyClass')->makePartial();

$this->mock ->shouldReceive('save') ->once() ->andReturn('true');

Constructor arguments$mock = \Mockery::mock('MyNamespace\MyClass[foo]', array($arg1, $arg2));

$experienceServiceMock = Mockery::mock(\App\Services\ExperienceService::class);$experienceServiceMock->shouldReceive('saveExperience')->times(1)->andReturn(false);$this->app->instance(\App\Services\ExperienceService::class, $experienceServiceMock);// Test$this->actingAs($user) ->withSession($sessionData) ->post(action('ExperienceController@postConfirm')) ->assertResponseStatus(500);

17

Thanks

• Thanks for coming!!!

top related