Laravel - Testing - Mocking (官方文件原子化翻譯)

# 前言

學習一個框架, Ray 的想法是, 在深入理解底層實作的原理之前, 應該先知道這個框架的 使用方法; 先學習怎麼使用這個前人造的輪子, 再學習怎麼樣一個輪子。
所以本篇文章重點在於細讀官方文件, 並將內容理解後以 Q&A 的方式記錄下來, 加速學習以及查詢。

# Mocking Objects

以下的 Laravel example code 的意思是?
  • Example:
    <?php
    use App\Service;
    use Mockery;
    use Mockery\MockInterface;

    public function test_something_can_be_mocked()
    {
    $this->instance(
    Service::class,
    Mockery::mock(Service::class, function (MockInterface $mock) {
    $mock->shouldReceive('process')->once();
    })
    );
    }
  • Answer:
    將 service::class 綁到 service container 當中, 當完成綁定後, service container 將會使用 mocked class, 而不是原本的 object, 並指定 process method 會被呼叫一次
以下的 Laravel example code 的意思是?
  • Example:
    <?php
    use App\Service;
    use Mockery\MockInterface;

    $mock = $this->mock(Service::class, function (MockInterface $mock) {
    $mock->shouldReceive('process')->once();
    });
  • Answer:
    將 service::class 綁到 service container 當中, 當完成綁定後, service container 將會使用 mocked class, 而不是原本的 object, 並指定 process method 會被呼叫一次
以下的 Laravel example code 的意思是?
  • Example:
    <?php
    use App\Service;
    use Mockery\MockInterface;

    $mock = $this->partialMock(Service::class, function (MockInterface $mock) {
    $mock->shouldReceive('process')->once();
    });
  • Answer:
    使用 partialMock() 將 Service::class 綁定 container, 所以 container 會使用 mocked class, 而不是實際上的 object, 並使用 shouldReceive() 宣告 process method 會被呼叫, once() 定義次數
    partialMock 只 mock 被呼叫的 method, 其他 method 如果在 testing 過程中有被呼叫, 則正常執行
以下的 Laravel example code 的意思是?
  • Example:
    <?php

    namespace Tests\Feature;

    use Illuminate\Foundation\Testing\RefreshDatabase;
    use Illuminate\Foundation\Testing\WithoutMiddleware;
    use Illuminate\Support\Facades\Cache;
    use Tests\TestCase;

    class UserControllerTest extends TestCase
    {
    public function testGetIndex()
    {
    Cache::shouldReceive('get')
    ->once()
    ->with('key')
    ->andReturn('value');

    $response = $this->get('/users');

    // ...
    }
    }
  • Answer:
    mock Cache facade, 並使用 shouldReceive 斷言 get() 將被呼叫, once() 代表次數, with() 代表 parameter, 而 return value 代表回傳的值, 如果沒有達到以上的斷言, 則 fail
Laravel testing 中, 如果要 mock config, 該使用?

config::set

Laravel testing 中, 如果要 mock http testing, 該使用?

http testing method


# Facade Spies

以下的 Laravel example code 的意思是?
  • Example:
    <?php
    use Illuminate\Support\Facades\Cache;

    public function test_values_are_be_stored_in_cache()
    {
    Cache::spy();

    $response = $this->get('/');

    $response->assertStatus(200);

    Cache::shouldHaveReceived('put')->once()->with('name', 'Taylor', 10);
    }
  • Answer:
    使用 spy() method 來紀錄下所有 testing 過程與 Cache facade 的互動, 並在最後 assert, 若不符合 assertion 則報錯

# Bus Fake

以下的 Laravel example code 的意思是?
  • Example:
    <?php

    namespace Tests\Feature;

    class ExampleTest extends TestCase
    {
    public function test_orders_can_be_shipped()
    {
    Bus::fake();

    // Perform order shipping...

    Bus::assertDispatched(ShipOrder::class);

    Bus::assertNotDispatched(AnotherJob::class);
    }
    }
  • Answer:
    使用 Bus facade 的 fake(), 任何使用到 Bus facade dispatch 的 job 將不會真正的被 dispatch
    最後可使用 assertDispatched(), assertNotDispatched() 來斷言哪個 job 被 dispatch 了, 哪個沒有
以下的 Laravel testing example code 的意思是?
  • Example:
    <?php
    Bus::assertDispatched(function (ShipOrder $job) use ($order) {
    return $job->order->id === $order->id;
    });
  • Answer:
    當使用 Bus facade 的 assertDispatched(), assertNotDispatched() 時, 可帶入 closure 來判定被 dispatched 的 job 有通過一定的規則

# Job Chains

以下的 Laravel example code 的意思是?
  • Example:
    <?php
    use App\Jobs\RecordShipment;
    use App\Jobs\ShipOrder;
    use App\Jobs\UpdateInventory;
    use Illuminate\Support\Facades\Bus;

    Bus::assertChained([
    ShipOrder::class,
    RecordShipment::class,
    UpdateInventory::class
    ]);
  • Answer:
    assert 指定的 job 有被 chained 且 dispatched
以下的 Laravel example code 的意思是?
  • Example:
    <?php
    Bus::assertChained([
    new ShipOrder,
    new RecordShipment,
    new UpdateInventory,
    ]);
  • Answer:
    assert 指定的 job 有被 chained 且 dispatched, 除了可帶入 class name, 也可帶入 class instance

# Job Batches

以下的 Laravel example code 的意思是?
  • Example:
    <?php
    use Illuminate\Bus\PendingBatch;
    use Illuminate\Support\Facades\Bus;

    Bus::assertBatched(function (PendingBatch $batch) {
    return $batch->name == 'import-csv' &&
    $batch->jobs->count() === 10;
    });
  • Answer:
    使用 assertBatched() 來斷言 batch of jobs 已被 dispatched, 可在 closure 內取得 PendingBatch, 取得該 batch 的資料, 並定義該 batch 應該要有的條件

# Event Fake

以下的 Laravel example code 的意思是?
  • Example:
    <?php

    class ExampleTest extends TestCase
    {
    public function test_orders_can_be_shipped()
    {
    Event::fake();

    // Perform order shipping...

    Event::assertDispatched(OrderShipped::class);

    Event::assertDispatched(OrderShipped::class, 2);

    Event::assertNotDispatched(OrderFailedToShip::class);

    Event::assertNothingDispatched();
    }
    }
  • Answer:
    使用 fake(), 則該 event 的 listener 將不會真正的 dispatch
    assertDispatched() 斷言指定的 event 需被 dispatched
    assertDispatched() arg2 代表該 event 需被 dispatched 2 次
    assertNotDispatched 斷言該 event 沒被 dispatched
    assertNothingDispatched 斷言沒有任何 event 被 dispatched
以下的 Laravel testing example code 的意思是?
  • Example:
    <?php
    Event::assertDispatched(function (OrderShipped $event) use ($order) {
    return $event->order->id === $order->id;
    });
  • Answer:
    使用 closure 來斷言, 符合定義條件的 job 有被 dispatched
以下的 Laravel testing example code 的意思是?
  • Example:
    <?php
    Event::assertListening(
    OrderShipped::class,
    [SendShipmentNotification::class, 'handle']
    );
  • Answer:
    斷言指定的 listener 有 listen 定義的 event
以下的 Laravel testing 中, 如果有使用到 Factory 的 model event, Event::fake() 需使用在 Factory 之後, 原因為何?

因為一旦使用了 Event::fake(), 所有 event 都不會被執行

# Faking A Subset Of Events

以下的 Laravel testing example code 的意思是?
  • Example:
    <?php
    public function test_orders_can_be_processed()
    {
    Event::fake([
    OrderCreated::class,
    ]);

    $order = Order::factory()->create();

    Event::assertDispatched(OrderCreated::class);

    // Other events are dispatched as normal...
    $order->update([...]);
    }
  • Answer:
    可帶入 class 到 Event::fake(), 這樣只有該 event 會被 fake, 其餘的 event 照常執行

Scoped Event Fakes

以下的 Laravel testing example code 的意思是?
  • Example:
    <?php

    class ExampleTest extends TestCase
    {
    public function test_orders_can_be_processed()
    {
    $order = Event::fakeFor(function () {
    $order = Order::factory()->create();

    Event::assertDispatched(OrderCreated::class);

    return $order;
    });

    $order->update([...]);
    }
    }
  • Answer:
    只有 fakeFor() 內, closure 範圍內的 event 才會被 fake, 其餘的照常執行

# HTTP Fake

可參考 Fake HTTP Client


# Mail Fake

以下的 Laravel testing example code 的意思是?
  • Example:
    <?php
    public function test_orders_can_be_shipped()
    {
    Mail::fake();

    Mail::assertNothingSent();

    Mail::assertSent(OrderShipped::class);

    Mail::assertSent(OrderShipped::class, 2);

    Mail::assertNotSent(AnotherMailable::class);
    }
  • Answer:
    使用 Mail::fake(), 模擬 mail 寄出 testing, 實際上不會真的寄出
    assert 沒有任何 mailable 被送出
    assert 指定的 mailable 被發送
    assert 指定的 mailable 被發送兩次
    assert 指定的 mailable 沒有被送出
以下的 Laravel testing example code 的意思是?
  • Example:
    <?php
    Mail::assertQueued(OrderShipped::class);

    Mail::assertNotQueued(OrderShipped::class);

    Mail::assertNothingQueued();
  • Answer:
    當要測試用 queue 發送的 mailable 時, 使用 assertQueued()
    assert OrderShipped mailable 由 queue 發送
    assert OrderShipped mailable 沒有由 queue 發送
    assert 沒有任何 mailable 經由 queue 被發送
以下的 Laravel testing example code 的意思是?
  • Example:
    <?php
    Mail::assertSent(function (OrderShipped $mail) use ($order) {
    return $mail->order->id === $order->id;
    });
  • Answer:
    assertSent 以及 assertNotSent 也可帶入 closure, 判斷是否有通過 closure 內條件的 mailable 被發送
以下的 Laravel testing example code 的意思是?
  • Example:
    <?php
    Mail::assertSent(OrderShipped::class, function ($mail) use ($user) {
    return $mail->hasTo($user->email) &&
    $mail->hasCc('...') &&
    $mail->hasBcc('...');
    });
  • Answer:
    除了 assert 指定 mailable 被送出外, 還可以 assert
    寄給誰
    cc 給誰
    bcc 給誰

# Notification Fake

以下的 Laravel testing example code 的意思是?
  • Example:
    <?php
    public function test_orders_can_be_shipped()
    {
    Notification::fake();

    // Perform order shipping...

    Notification::assertNothingSent();

    Notification::assertSentTo(
    [$user], OrderShipped::class
    );

    Notification::assertNotSentTo(
    [$user], AnotherNotification::class
    );
    }
  • Answer:
    使用 Notification::fake()
    斷言沒有任何 notification sent
    斷言指定的 notification sent to a given user
    斷言指定的 notification not sent to a given user
以下的 Laravel testing example code 的意思是?
  • Example:
    <?php
    Notification::assertSentTo(
    $user,
    function (OrderShipped $notification, $channels) use ($order) {
    return $notification->order->id === $order->id;
    }
    );
  • Answer:
    assertSentTo 可帶入 closure, 若有符合 closure 內條件的 mailable sent, 則 assertion 成立

# On-Demand Notifications

以下的 Laravel testing example code 的意思是?
  • Example:
    <?php
    use Illuminate\Notifications\AnonymousNotifiable;

    Notification::assertSentTo(
    new AnonymousNotifiable, OrderShipped::class
    );
  • Answer:
    當測試 On-Demand notification 時, 原本帶入 user 的 arg1, 改帶入 AnonymousNotifiable instance
以下的 Laravel testing example code 的意思是?
  • Example:
    <?php
    Notification::assertSentTo(
    new AnonymousNotifiable,
    OrderShipped::class,
    function ($notification, $channels, $notifiable) use ($user) {
    return $notifiable->routes['mail'] === $user->email;
    }
    );
  • Answer:
    當測試 on-demand notification 時, 可帶入 closure, assert 實際上發送的 mail 與指定 user 的 mail 相同

# Queue Fake

以下的 Laravel testing example code 的意思是?
  • Example:
    <?php
    public function test_orders_can_be_shipped()
    {
    Queue::fake();

    // Perform order shipping...

    Queue::assertNothingPushed();

    Queue::assertPushedOn('queue-name', ShipOrder::class);

    Queue::assertPushed(ShipOrder::class, 2);

    Queue::assertNotPushed(AnotherJob::class);
    }
  • Answer:
    fake queue facade, 所以不會真的把 job push 到 queue 當中
    assert 沒有任何 job 被 push
    assert ShipOrder job 被 push 到 queue-name
    assert ShipOrder job 被 push 兩次
    assert AnotherJob 沒有被 push
以下的 Laravel testing example code 的意思是?
  • Example:
    <?php
    Queue::assertPushed(function (ShipOrder $job) use ($order) {
    return $job->order->id === $order->id;
    });
  • Answer:
    可 pass closure 到 assertPushed(), assertNotPushed(), 更明確的斷言是哪些 job 被 push 或沒被 push

# Job Chains

以下的 Laravel testing example code 的意思是?
  • Example:
    <?php
    Queue::assertPushedWithChain(ShipOrder::class, [
    RecordShipment::class,
    UpdateInventory::class
    ]);
  • Answer:
    斷言哪些 queue 被 queue chained, arg1 為第一個 job, arg2 為其餘的 jobs
以下的 Laravel testing example code 的意思是?
  • Example:
    <?php
    Queue::assertPushedWithChain(ShipOrder::class, [
    new RecordShipment,
    new UpdateInventory,
    ]);
  • Answer:
    assertPushedWithChain() 可 pass class name, 也可 pass instance
以下的 Laravel testing example code 的意思是?
  • Example:
    <?php
    Queue::assertPushedWithoutChain(ShipOrder::class);
  • Answer:
    使用 assertPushedWithoutChain() 來斷言 ShipOrder job 沒有被 chained

# Storage Fake

以下的 Laravel testing example code 的意思是?
  • Example:
    <?php
    public function test_albums_can_be_uploaded()
    {
    Storage::fake('photos');

    $response = $this->json('POST', '/photos', [
    UploadedFile::fake()->image('photo1.jpg'),
    UploadedFile::fake()->image('photo2.jpg')
    ]);

    Storage::disk('photos')->assertExists('photo1.jpg');
    Storage::disk('photos')->assertExists(['photo1.jpg', 'photo2.jpg']);

    Storage::disk('photos')->assertMissing('missing.jpg');
    Storage::disk('photos')->assertMissing(['missing.jpg', 'non-existing.jpg']);
    }
  • Answer:
    使用 Storage fake() 一個 fake disk
    產生 fake image
    斷言 fake disk photos 存在某些檔案
    斷言 fake disk photos 不存在某些檔案
以下的 Laravel testing example code 的意思是?
  • Example:
    <?php
    $response = $this->json('POST', '/photos', [
    UploadedFile::fake()->image('photo1.jpg'),
    UploadedFile::persistentFake()->image('photo2.jpg')
    ]);
  • Answer:
    使用 fake 時, 該 fake file 會在 testing 結束後從 temp dir 中被刪除
    若要保留, 可使用 persistentFake()

# Interacting With Time

以下的 Laravel testing example code 的意思是?
  • Example:
    <?php
    public function testTimeCanBeManipulated()
    {
    $this->travel(5)->milliseconds();
    $this->travel(5)->seconds();
    $this->travel(5)->minutes();
    $this->travel(5)->hours();
    $this->travel(5)->days();
    $this->travel(5)->weeks();
    $this->travel(5)->years();

    $this->travel(-5)->hours();

    $this->travelTo(now()->subHours(6));

    $this->travelBack();
    }
  • Answer:
    <?php
    public function testTimeCanBeManipulated()
    {
    // Travel into the future...
    $this->travel(5)->milliseconds();
    $this->travel(5)->seconds();
    $this->travel(5)->minutes();
    $this->travel(5)->hours();
    $this->travel(5)->days();
    $this->travel(5)->weeks();
    $this->travel(5)->years();

    // Travel into the past...
    $this->travel(-5)->hours();

    // Travel to an explicit time...
    $this->travelTo(now()->subHours(6));

    // Return back to the present time...
    $this->travelBack();
    }

可使用 travel() method, 定義當前時間以方便測試


# Additional

以下的 Laravel example code 的意思是?
  • Example:
    <?php
    $mock = \Mockery::mock('MyClass');
    $mock->shouldReceive('name_of_method')
    ->andSet($property, $value);
    // or
    $mock->shouldReceive('name_of_method')
    ->set($property, $value);
  • Answer:
    給 mock object 設定 public property
以下的 Laravel example code 的意思是?
  • Example:
    <?php
    $mock = \Mockery::mock('MyClass');
    $mock->shouldReceive('name_of_method')
    ->andThrow('exception_name', 'message', 123456789);
  • Answer:
    定義指定的 method return 指定的 exception, message, 以及 status code
以下的 Laravel example code 的意思是?
  • Example:
    <?php
    $mock = \Mockery::mock('MyClass');
    $mock->shouldReceive('name_of_method')
    ->andThrow(new Exception);
  • Answer:
    定義指定的 mock method return 指定的 exception
以下的 Laravel example code 的意思是?
  • Example:
    <?php
    $mock = \Mockery::mock('MyClass');
    $mock->shouldReceive('name_of_method')
    ->andReturnSelf();

  • Answer:
    return mock class name
以下的 Laravel example code 的意思是?
  • Example:
    <?php
    $mock = \Mockery::mock('MyClass');
    $mock->shouldReceive('name_of_method')
    ->andReturnArg(1);
  • Answer:
    定義 return value 為 index 1 的 arg
以下的 Laravel example code 的意思是?
  • Example:
    <?php
    $mock = \Mockery::mock('MyClass');
    $mock->shouldReceive('name_of_method')
    ->andReturnUsing(closure, ...);
  • Answer:
    若要對 return value 做計算, 可使用 andReturnUsing()
以下的 Laravel example code 的意思是?
  • Example:
    <?php
    $mock = \Mockery::mock('MyClass');
    $mock->shouldReceive('name_of_method')
    ->andReturnNull();
    // or
    $mock->shouldReceive('name_of_method')
    ->andReturn([null]);
  • Answer:
    定義 method return value 為 null
以下的 Laravel example code 的意思是?
  • Example:
    <?php
    $mock = \Mockery::mock('MyClass');
    $mock->shouldReceive('name_of_method')
    ->andReturnValues([$value1, $value2, ...])
  • Answer:
    使用 andReturn() 定義 return value, 會按順序 return $value, 若呼叫次數大於定義 value 數量, 會總回傳最後一個 value
以下的 Laravel example code 的意思是?
  • Example:
    <?php
    $mock = \Mockery::mock('MyClass');

    $mock->shouldReceive('foo')->andReturn(1, 2, 3);

    $mock->foo(); // int(1)
    $mock->foo(); // int(2)
    $mock->foo(); // int(3)
    $mock->foo(); // int(3)
  • Answer:
    使用 andReturn() 定義 return value, 會按順序 return $value, 若呼叫次數大於定義 value 數量, 會總回傳最後一個 value
以下的 Laravel example code 的意思是?
  • Example:
    <?php
    $mock = \Mockery::mock('MyClass');
    $mock->shouldReceive('name_of_method')
    ->andReturn($value1, $value2, ...)
  • Answer:
    andReturn() 亦可定義多個回傳值, 第一次呼叫回傳 $value1, 第二次 value2, 以此類推
以下的 Laravel example code 的意思是?
  • Example:
    <?php
    $mock = \Mockery::mock('MyClass');
    $mock->shouldReceive('name_of_method')
    ->andReturn($value);
  • Answer:
    andReturn() 定義回傳值
以下的 Laravel example code 的意思是?
  • Example:
    <?php
    $mock = \Mockery::mock('MyClass');
    $mock->shouldReceive('name_of_method')
    ->withNoArgs();
  • Answer:
    定義 expectation, 該 method 沒有 args
以下的 Laravel example code 的意思是?
  • Example:
    <?php
    $mock = \Mockery::mock('MyClass');
    $mock->shouldReceive('name_of_method')
    ->withAnyArgs();
  • Answer:
    定義 expectation, 該 method 不管 pass 什麼 arg 都可以
以下的 Laravel example code 的意思是?
  • Example:
    <?php
    $mock = \Mockery::mock('MyClass');
    $mock->shouldReceive('name_of_method')
    ->withAnyArgs();
  • Answer:
    定義 expectation, 該 method 不管 pass 什麼 arg 都可以
以下的 Laravel example code 的意思是?
  • Example:
    <?php
    $mock = \Mockery::mock('MyClass');
    $mock->shouldReceive('foo')
    ->withSomeOfArgs(1, 2);

    $mock->foo(1, 2, 3);
    $mock->foo(3, 2, 1);
    $mock->foo('1', '2');
    $mock->foo(3);
  • Answer:
    判斷實際上有無帶入 withSomeOfArgs() 定義的 method, 有包含即可, 多帶也可, 少了就不行
    // matches the expectation
    // matches the expectation (passed order doesn’t matter)
    // throws a NoMatchingExpectationException (type should be matched)
    // throws a NoMatchingExpectationException######

以下的 Laravel example code 的意思是?

  • Example:
    <?php
    $mock = \Mockery::mock('MyClass');
    $mock->shouldReceive('name_of_method')
    ->withArgs(closure);
  • Answer:
    withArgs() 內也可帶入 closure, closure return 將帶入的 args, 不符合則報錯
以下的 Laravel example code 的意思是?
  • Example:
    <?php
    $mock = \Mockery::mock('MyClass');

    $mock->shouldReceive('foo')->with('Hello');

    $mock->foo('Goodbye'); // throws a NoMatchingExpectationException
  • Answer:
    使用 with() 來定義將帶入 mocked method 的 args, 若不符合則報錯
以下的 Laravel example code 的意思是?
  • Example:
    <?php
    $mock = \Mockery::mock('MyClass');
    $mock->shouldReceive('name_of_method')
    ->with($arg1, $arg2, ...);
    // or
    $mock->shouldReceive('name_of_method')
    ->withArgs([$arg1, $arg2, ...]);
  • Answer:
    使用 with() 或 withArgs() 來定義將帶入 mocked method 的 args, 若不符合則報錯
以下的 Laravel example code 的意思是?
  • Example:
    <?php
    $mock = \Mockery::mock('MyClass');
    $mock->shouldNotReceive('name_of_method');
  • Answer:
    定義指定 method 不該被呼叫
以下的 Laravel example code 的意思是?
  • Example:
    <?php
    $mock = \Mockery::mock('MyClass', ['name_of_method_1' => 'return value 1', 'name_of_method_2' => 'return value 2']);
  • Answer:
    定義多個 expectation 以及其 shortcut
以下的 Laravel example code 的意思是?
  • Example:
    <?php
    $mock = \Mockery::mock('MyClass');
    $mock->shouldReceive([
    'name_of_method_1' => 'return value 1',
    'name_of_method_2' => 'return value 2',
    ]);
  • Answer:
    可定義多個 expectation 以及其 return value
以下的 Laravel example code 的意思是?
  • Example:
    <?php
    $mock = \Mockery::mock('MyClass');
    $mock->shouldReceive('name_of_method_1', 'name_of_method_2');
  • Answer:
    可以定義多個 expectation
以下的 Laravel example code 的意思是?
  • Example:
    <?php
    \Mockery::mock('MyClass')->shouldIgnoreMissing()->asUndefined();
  • Answer:
    PHP 7.0 ~ 7.1 的版本, 會根據不同的 type 回傳不同的值, 可使用 asUndefined() 一律回傳 null
以下的 Laravel example code 的意思是?
  • Example:
    <?php
    \Mockery::mock('MyClass')->shouldIgnoreMissing();
  • Answer:
    將 MyClass 中沒有定義 expectation 的 method, 一律 return null
    與 makePartial 的差異在於, makePartial() 會去呼叫 parent class, 而 shouldIgnoreMissing() 則是 return null
以下的 Laravel example code 的意思是?
  • Example:
    <?php
    $mock = \Mockery::mock('MyClass', [$constructorArg1, $constructorArg2]);
    $mock = \Mockery::mock('MyClass', 'MyInterface', [$constructorArg1, $constructorArg2]);
  • Answer:
    當 mock class 時, 可 pass constructor arguments
以下的 Laravel example code 的意思是?
  • Example:
    <?php
    // 待測 class
    class Fetcher
    {
    const SUCCESS = 0;
    const FAILURE = 1;

    public function fetch()
    {
    // Fetcher gets something for us from somewhere...
    return self::SUCCESS;
    }
    }

    // testing code
    \Mockery::getConfiguration()->setConstantsMap([
    'Fetcher' => [
    'SUCCESS' => 'success',
    'FAILURE' => 'fail',
    ]
    ]);

    $mock = \Mockery::mock('Fetcher');
    var_dump($mock::SUCCESS); // (string) 'success'
    var_dump($mock::FAILURE); // (string) 'fail'
  • Answer:
    Mockery 預設並不會 mock class constant, 因此使用 setConstantsMap() 來定義 class constant
以下的 Laravel example code 的意思是?
  • Example:
    <?php
    // to-be test class
    class Fetcher
    {
    const SUCCESS = 0;
    const FAILURE = 1;

    public function fetch()
    {
    // Fetcher gets something for us from somewhere...
    return self::SUCCESS;
    }
    }

    class MyClass
    {
    public function doFetching($fetcher)
    {
    $response = $fetcher->fetch();

    if ($response == Fetcher::SUCCESS) {
    echo "Thanks!" . PHP_EOL;
    } else {
    echo "Try again!" . PHP_EOL;
    }
    }
    }

    // test
    class FetcherStub
    {
    const SUCCESS = 0;
    const FAILURE = 1;
    }

    $mock = \Mockery::nameMock('Fetcher', 'FetcherStub')
    $mock->shouldReceive('fetch')
    ->andReturn(0);

    $myClass = new MyClass();
    $myClass->doFetching($mock);

  • Answer:
    Mockery 當 mock 一個 class 時, 並不會 mock class constant, 因此可以建立一個 stub class, 裡頭定義 class contant, 並使用 nameMock() 來 mock 待測的 class, 並 extend stub class
以下的 Laravel example code 的意思是?
  • Example:
    <?php
    class ClassToTest {

    public function methodToTest()
    {
    return MyClass::someStaticMethod();
    }
    }

    public function testNewMethodToTest()
    {
    $mock = Mockery::mock('alias:MyClass');
    $mock->shouldreceive('someStaticMethod')->andReturn('someResult');

    $classToTest = new ClassToTest();
    $result = $classToTest->methodToTest();

    $this->assertEquals('someResult', $result);
    }
  • Answer:
    使用 alias 來 test public static method
以下的 Laravel example code 的意思是?
  • Example:
    <?php
    class ClassToTest
    {
    public function methodToTest()
    {
    $myClass = new MyClass();
    $result = $myClass->someMethod();
    return $result;
    }
    }

    public function testMethodToTest()
    {
    $mock = Mockery::mock('overload:MyClass');
    $mock->shouldreceive('someMethod')->andReturn('someResult');

    $classToTest = new ClassToTest();
    $result = $classToTest->methodToTest();

    $this->assertEquals('someResult', $result);
    }
  • Answer:
    使用 overload make an instance mock, 當一個 class 被建立, 會使用 overload mock 來替代這個 class
以下的 Laravel example code 的意思是?
  • Example:
    <?php
    $mock = \Mockery::mock(new MyClass);
  • Answer:
    如果該 class 或其 method 已被 marked final, 可以 mock new class, 但這個 mock class 的 type hint check 將無作用
以下的 Laravel example code 的意思是?
  • Example:
    <?php
    class Foo {
    function foo() { return 123; }
    function bar() { return $this->foo(); }
    }

    $foo = mock("Foo[!foo]");

    $foo->foo(); // int(123)

    $foo->bar(); // error, no expectation set
  • Answer:
    指定除了 foo method 之外的 method 都 mock, 但建議使用 runtime partial, 因為直接 mock 特定的 method 會去呼叫 origin constructor, 可能會有意料外的行為
以下的 Laravel example code 的意思是?
  • Example:
    <?php
    class Foo {
    function foo() { return 123; }
    function bar() { return $this->foo(); }
    }

    $foo = mock("Foo[foo]");

    $foo->foo(); // error, no expectation set

    $foo->shouldReceive('foo')->andReturn(456);
    $foo->foo(); // int(456)

    // setting an expectation for this has no effect
    $foo->shouldReceive('bar')->andReturn(999);
    $foo->bar(); // int(456)
  • Answer:
    可以 mock 特定的 class 中的 method, 但建議使用 runtime partial, 因為直接 mock 特定的 method 會去呼叫 origin constructor, 可能會有意料外的行為
以下的 Laravel example code 的意思是?
  • Example:
    <?php
    class BigParentClass
    {
    public function doesEverything()
    {
    // sets up database connections
    // writes to log files
    }
    }

    class ChildClass extends BigParentClass
    {
    public function doesOneThing()
    {
    // but calls on BigParentClass methods
    $result = $this->doesEverything();
    // does something with $result
    return $result;
    }
    }

    $childClass = \Mockery::mock('ChildClass')->makePartial();
    $childClass->shouldReceive('doesEverything')
    ->andReturn('some result from parent');

    $childClass->doesOneThing(); // string("some result from parent");
  • Answer:
    建立一個 runtime partial test double of ChildClass, 並且只 mock doesEverything method
以下的 Laravel example code 的意思是?
  • Example:
    <?php
    $mock = \Mockery::mock('MyClass');
    $spy = \Mockery::spy('MyClass');

    $mock->shouldReceive('foo')->andReturn(42);

    $mockResult = $mock->foo();
    $spyResult = $spy->foo();

    $spy->shouldHaveReceived()->foo();

    var_dump($mockResult); // int(42)
    var_dump($spyResult); // null
  • Answer:
    spy always return null as the result of method
以下的 Laravel example code 的意思是?
  • Example:
    <?php
    $spy = \Mockery::spy('MyClass, MyInterface, OtherInterface');
  • Answer:
    建立一個 spy, type 為 MyClass, implement MyInterface 跟 OtherInterface
以下的 Laravel example code 的意思是?
  • Example:
    <?php
    $mock = \Mockery::mock('MyClass, MyInterface, OtherInterface');
  • Answer:
    mock MyClass, 且 implement MyInterface 以及 OtherInterface
以下的 Laravel example code 的意思是?
  • Example:
    <?php
    php artisan queue:work --name=notifications
  • Answer:
    給 worker 一個名字, 更易於 identified
以下的 Laravel example code 的意思是?
  • Example:
    <?php
    dispatch(
    new SendInvoice($order)
    )->afterCommit();
  • Answer:
    使用 dispatch(), 在所有 transaction 都 commit 之後才 dispatch 該 job
以下的 Laravel example code 的意思是?
  • Example:
    <?php
    dispatch(
    new SendInvoice($order)
    )->afterResponse();
  • Answer:
    使用 dispatch(), 在 connection close 之後, 保持 PHP process alive 來執行 job, 建議只執行簡單的 job
以下的 Laravel example code 的意思是?
  • Example:
    <?php
    Bus::chain([
    new DownloadRepo,
    new RunTests,
    new Deploy
    ])->dispatch()
  • Answer:
    使用 Bus::chain() dispatch chained job, job 會按順序執行
以下的 Laravel example code 的意思是?
  • Example:
    <?php
    class OrderController
    {
    public function store()
    {
    // ...
    Bus::dispatchAfterResponse(new ReleaseLocks());
    return response('OK!');
    }
    }
  • Answer:
    如果 job 很簡單, 可以不需要 dispatch 到 queue, 而是在 response 後處理
    當 close connection with browser 後, 保持 PHP process alive 執行該 job
    但如果該 job 不是很簡短, 那還是建議跑 queue
以下的 example 中, 若 RestartNginx job 沒有 use InteractWithQueue, 以及 Queueable trait, 那 Bus 會使用哪個 driver dispatch 該 job?
  • Example:
    <?php
    class DeployProject implements ShouldQueue
    {
    public function handle()
    {
    // Deployment logic...
    Bus::dispatchNow(new RestartNginx());
    }
    }
  • Answer:
    會直接 invoke, 不會觸發 queue event
Laravel queue 中, 當 dispatch with sync queue driver, 會觸發 job failed event 嗎?

Laravel queue 中, 當 dispatch with sync queue driver, 會觸發 queue event 嗎?

以下的 example 中, 若 RestartNginx job use InteractWithQueue, 以及 Queueable trait, 那 Bus 會使用哪個 driver dispatch 該 job?
  • Example:
    <?php
    class DeployProject implements ShouldQueue
    {
    public function handle()
    {
    // Deployment logic...
    Bus::dispatchNow(new RestartNginx());
    }
    }
  • Answer:
    sync queue driver
以下的 Laravel example code 的意思是?
  • Example:
    <?php
    use Illuminate\Support\Facades\Bus;
    Bus::dispatchToQueue(
    new SendInvoice($order)
    );
  • Answer:
    使用 Bus facade 來 dispatch a single job
以下的 Laravel example code 的意思是?
  • Example:
    <?php
    class TenancyProvider extends ServiceProvider
    {
    public function boot()
    {
    Queue::createPayloadUsing(function () {
    return ['tenant_id' => Tenant::get()->id];
    });

    Event::listen(JobProcessing::class, function ($event){
    $tenant = Tenant::find(
    $event->job->payload()['tenant_id']
    );

    $tenant->configureDatabaseConnection();

    $tenant->setAsCurrent();
    });
    }
    }
  • Answer:
    listen job processed event, 在該 job 被 pick up 但還未執行前, 設定特定資料庫的連線
    使用 Queue::createPayloadUsing() 來 insert tenant_id 到 raw payload, 之後當 worker 取出該 job, 就可以透過先前 insert 的 tenant_id 來取得 tenant, 並完成連線設定
以下的 Laravel example code 的意思是?
  • Example:
    <?php
    class ResetStateMiddleware
    {
    public function handle($job, $next)
    {
    app()->setLocale('en');
    Vendor::$name = 'Laravel';

    return $next($job);
    }
    }
  • Answer:
    因為 worker 是一個 process, 不會隨著 job 完成就釋放, 因此像是 static property 會改變 之後 worker 的狀態, 包括所以務必在處理完當下 job 之後, 把狀態改回來
    使用 middleware 的方式在每次 job 執行前 reset locale
以下的 Laravel example code 的意思是?
  • Example:
    <?php
    class SendReport
    {
    public function handle()
    {
    Vendor::$name = $this->vendor->name;
    // Run the job logic...
    Vendor::$name = 'Laravel';
    }

    public function failed($e)
    {
    Vendor::$name = 'Laravel';
    }
    }
  • Answer:
    因為 worker 是一個 process, 不會隨著 job 完成就釋放, 因此像是 static property 會改變 之後 worker 的狀態, 包括所以務必在處理完當下 job 之後, 把狀態改回來
以下的 Laravel example code 的意思是?
  • Example:
    <?php
    class SendReport
    {
    public function __construct($report, $locale)
    {
    // ...
    }

    public function handle()
    {
    app()->setLocale($this->locale);
    // Run the job logic...
    app()->setLocale('en');
    }
    }
  • Answer:
    因為 worker 是一個 process, 不會隨著 job 完成就釋放, 因此像是 app()->setLocale() 這種 global method 會改變 worker 的狀態, 包括所以務必在處理完當下 job 之後, 把狀態改回來
以下的 Laravel job 中, 何謂 idempotent job?

表示不管執行幾次都不會有副作用, 像是

public function handle()
{
if ($this->invoice->refunded) {
return $this->delete();
}

$this->invoice->refund();
}
以下的 Laravel example code 的意思是?
  • Example:
    <?php
    class GenerateReport implements ShouldQueue
    {
    use SerializesModels;
    public function __construct(Report $report)
    {
    $this->report = $report;
    }
    public function handle()
    {
    app(
    \Illuminate\Contracts\Cache\Factory::class
    )->get(...);
    }
    }

  • Answer:
    若使用 dependency injection, Factory 會需要經過 unserialised / serialised, 會增加很大的 CPU overhead, 若使用 service container 對 worker 來說會非常簡單
    Model 部分, 使用 SerializesModels trait, 只 pass model identifier, 等到 execute 時在取出相對應的 model, 同樣降低很多的 overhead
Laravel testing 中, 如果呼叫了沒使用 shouldHaveReceived 定義的 method, 會噴錯嗎?

不會, 除非使用 shouldNotHaveReceived()

Laravel testing 中, 如果呼叫了沒使用 shouldReceive 定義的 method, 會噴錯嗎?

以下的 Laravel example code 的意思是?
  • Example:
    <?php
    // class
    class Reservation
    {
    public $tickets;
    public $email;

    public function __construct($tickets, $email)
    {
    $this->tickets = $tickets;
    $this->email = $email;
    }

    public function complete($paymentGateway, $paymentToken)
    {
    $charge = $paymentGateway->charge($this->totalPrice(), $paymentToken);
    return Order::forReservation($this, $charge);
    }

    private function totalPrice()
    {
    return $this->tickets->sum('price');
    }
    }

    // test
    class ReservationTest extends PHPUnit_Framework_TestCase
    {
    function test_the_reservation_is_completed_successfully()
    {
    // Arrange
    $tickets = collect([
    ['price' => 1250],
    ['price' => 1250],
    ['price' => 1250],
    ]);

    $paymentGateway = Mockery::spy('PaymentGateway');

    // Act
    $reservation = new Reservation($tickets, 'adam@example.com');
    $order = $reservation->complete($paymentGateway, 'tok_valid-token');

    // Assert
    $this->assertEquals('adam@example.com', $order->email);
    $paymentGateway->shouldHaveReceived('charge')->with(3750, 'tok_valid-token')->once();
    }
    }
  • Answer:
    使用 spy() 來記下所有 paymentGateway class 在這個 test 過程中的 interaction
    使用 shouldHaveReceived() 來判定上述的 interaction 中, 是否 charge method 有被呼叫
    使用 with() 來判定, 是否 interaction 中, 有帶入指定的 parameter
    使用 once() 來判定, 在 interaction 中, 是否有被呼叫一次
以下的 Laravel example code 的意思是?
  • Example:
    <?php
    // class
    class Reservation
    {
    public $tickets;
    public $email;

    public function __construct($tickets, $email)
    {
    $this->tickets = $tickets;
    $this->email = $email;
    }

    public function complete($paymentGateway, $paymentToken)
    {
    $charge = $paymentGateway->charge($this->totalPrice(), $paymentToken);
    return Order::forReservation($this, $charge);
    }

    private function totalPrice()
    {
    return $this->tickets->sum('price');
    }
    }

    // test
    class ReservationTest extends PHPUnit_Framework_TestCase
    {
    function test_the_reservation_is_completed_successfully()
    {
    $tickets = collect([
    ['price' => 1250],
    ['price' => 1250],
    ['price' => 1250],
    ]);

    $paymentGateway = Mockery::mock('PaymentGateway');
    $paymentGateway->shouldReceive('charge')->with(3750, 'tok_valid-token')->once();

    $reservation = new Reservation($tickets, 'adam@example.com');
    $order = $reservation->complete($paymentGateway, 'tok_valid-token');
    }
    }
  • Answer:
    mock PaymentGateway, 所以該 class 不會真的被呼叫
    使用 shouldReceive() 來定義 mock PaymentGateway 在這個 test 中會被呼叫哪個 method
    with() 定義了將會帶進去的參數
    once() 表示呼叫一次
    如果跟以上的定義不相符, 則噴錯
何謂單元測試 3A 原則?

Arrange, Act, Assert

Laravel test mocking 中, spy 與 mock 的差異是?

mock 預先定義 mocked class 中使用 shouldReceive(), with() 指定 method 應該 如何 被呼叫, 包含 parameter 以及次數, 以及 return 值, 若不相符則 fail
spy 則是會自動在過程中記下 mocked class 指定的 method 被帶入什麼值, 在最後可以使用 shouldHaveReceived 來判斷帶入值與結果是否跟預料的是一樣

以下的 Laravel example code 的意思是?
  • Example:
    <?php
    $mock = \Mockery::mock('MyClass');
    $mock->shouldReceive('name_of_method')
    ->between($min, $max);
  • Answer:
    mock ‘MyClass’ class, 並斷言 ‘name_of_method’ method 至少會被呼叫 $min 次, 最多 $max 次, 若不符合則報錯
以下的 Laravel example code 的意思是?
  • Example:
    <?php
    $mock = \Mockery::mock('MyClass');
    $mock->shouldReceive('name_of_method')
    ->atMost()
    ->times(3);
  • Answer:
    mock ‘MyClass’ class, 並斷言 ‘name_of_method’ method 最多會被呼叫 3 次, 若不符合則報錯
以下的 Laravel example code 的意思是?
  • Example:
    <?php
    $mock = \Mockery::mock('MyClass');
    $mock->shouldReceive('name_of_method')
    ->atLeast()
    ->times(3);
  • Answer:
    mock ‘MyClass’ class, 並斷言 ‘name_of_method’ method 至少會被呼叫 3 次, 若不符合則報錯
以下的 Laravel example code 的意思是?
  • Example:
    <?php
    $mock = \Mockery::mock('MyClass');
    $mock->shouldReceive('name_of_method')
    ->never();
  • Answer:
    mock ‘MyClass’ class, 並斷言 ‘name_of_method’ method 不會收到任何呼叫, 若不符合則報錯
以下的 Laravel example code 的意思是?
  • Example:
    <?php
    $mock = \Mockery::mock('MyClass');
    $mock->shouldReceive('name_of_method')
    ->twice();
  • Answer:
    mock ‘MyClass’, 並斷言 ‘name_of_method’ method 將被呼叫 2 次, 若不符合則報錯
以下的 Laravel example code 的意思是?
  • Example:
    <?php
    $mock = \Mockery::mock('MyClass');
    $mock->shouldReceive('name_of_method')
    ->times($n);
  • Answer:
    mock ‘MyClass’, 並斷言 ‘name_of_method’ method 會被呼叫 ‘$n’ 次, 若不符合則報錯
Laravel Mockery 中, 務必在 each test 結束呼叫哪個 method, 否則 call count expectation 會無法正常運作?

\Mockery::close()

以下的 Laravel example code 的意思是?
  • Example:
    <?php
    $mock = \Mockery::mock('MyClass');
    $mock->shouldReceive('name_of_method')
    ->zeroOrMoreTimes();
  • Answer:
    mock MyClass, 並預測 name_of_method method 會被呼叫 0 或多次
以下的 Laravel example code 的意思是?
  • Example:
    <?php
    $helperMock = Mockery::mock('Acme\Helper');
    $helperMock
    ->shouldReceive('trans_c')
    ->once()
    ->passthru()
    ;
  • Answer:
    mock Helper class, 預設 trans_c 會被呼叫一次, 實際上 mock 只會判斷 trans_c 是否有被呼叫, 卻不會真正執行 trans_c(), 若有需求要執行 trans_c() 真正的程式碼, 可以加上 passthru()
以下的 Laravel example code 的意思是?
  • Example:
    <?php
    $mock = \Mockery::mock('foo')->shouldReceive('foo')->andReturn(1)->getMock();
  • Answer:
    取得 mock object from expectation chain
以下的 Laravel example code 的意思是?
  • Example:
    <?php
    $this->mock->shouldReceive('foo')->with('test1')->andReturn('bar1')->byDefault();
  • Answer:
    使用 byDefault() 可以省略掉在類似的 unit test 中不停的 mock 相同的 object
以下的 Laravel example code 的意思是?
  • Example:
    <?php
    $request = \Mockery::mock('Silhouette\Http\Request');
    $response = \Mockery::mock('Silhouette\Http\Response');
    $response->shouldReceive("setContent")->globally()->ordered();

    $db = \Mockery::mock('Dabble\Database');

    $configData = \Mockery::mock('Silhouette\Configuration\ConfigurationData');
    $configData->shouldReceive("get")->andReturn(array(18, 23))->globally()->ordered();
  • Answer:
    使用 ordered() 來定義 mock object method 被呼叫的順序, 若要在不同 mock object 排序, 可使用 globally()->ordered()
    若只需在同一個 mock object 排序, 只需使用 order()
以下的 Laravel example code 的意思是?
  • Example:
    <?php
    $mock = \Mockery::mock('MyClass');
    $mock->shouldReceive('foo')
    ->with(\Mockery::ducktype('foo', 'bar'));
  • Answer:
    可 pass object, 只要該 object 內有 expected 的 method, 就算符合, 若無則不
以下的 Laravel example code 的意思是?
  • Example:
    <?php
    $mock = \Mockery::mock('MyClass');
    $mock->shouldReceive('foo')
    ->with(\Mockery::pattern('/^foo/'));

    // Hamcrest equivalent
    $mock->shouldReceive('foo')
    ->with(matchesPattern('/^foo/'));
  • Answer:
    可使用 pattern(), 用 regular expression 來判斷 arg 是否符合 expectation
以下的 Laravel example code 的意思是?
  • Example:
    <?php
    $closure = function ($odd, $even, $sum = null) {
    $result = ($odd % 2 != 0) && ($even % 2 == 0);
    if (!is_null($sum)) {
    return $result && ($odd + $even == $sum);
    }
    return $result;
    };

    $mock = \Mockery::mock('MyClass');
    $mock->shouldReceive('foo')->withArgs($closure);

    $mock->foo(1, 2); // It matches the expectation: the optional argument is not needed
    $mock->foo(1, 2, 3); // It also matches the expectation: the optional argument pass the validation
    $mock->foo(1, 2, 4); // It doesn't match the expectation: the optional doesn't pass the validation
  • Answer:
    可以 pass closure 到 withArgs(), 若 return 值為 true, 則符合 expectation, 若 false 則不
以下的 Laravel example code 的意思是?
  • Example:
    <?php
    $mock = \Mockery::mock('MyClass');

    $mock->shouldReceive('foo')
    ->with(\Mockery::on(function ($argument) {
    if ($argument % 2 == 0) {
    return true;
    }
    return false;
    }));
  • Answer:
    當 return true 時, 符合 expectation, false 則報錯
    $mock->foo(4); // matches the expectation
    $mock->foo(3); // throws a NoMatchingExpectationException
以下的 Laravel example code 的意思是?
  • Example:
    <?php
    $mock = \Mockery::mock('MyClass');
    $mock->shouldReceive("foo")
    ->with(\Mockery::any());

    // Hamcrest equivalent
    $mock->shouldReceive("foo")
    ->with(anything())
  • Answer:
    不限制 arg type 或 value, 帶啥都行
以下的 Laravel example code 的意思是?
  • Example:
    <?php
    $mock->shouldReceive("foo")
    ->with(equalTo(new stdClass));
  • Answer:
    當 with() 帶入 object 時, 預設使用 strict comparison, 若要使用 loose comparison, 可使用 equalTo()
以下的 Laravel example code 的意思是?
  • Example:
    <?php
    $object = new stdClass();
    $mock = \Mockery::mock('MyClass');
    $mock->shouldReceive("foo")
    ->with($object);

    // Hamcrest equivalent
    $mock->shouldReceive("foo")
    ->with(identicalTo($object));
  • Answer:
    當 with() 帶入 object 時, 預設使用 strict comparison
以下的 Laravel example code 的意思是?
  • Example:
    <?php
    $mock = \Mockery::mock('MyClass');
    $mock->expects()
    ->name_of_method_1($arg1)
    ->twice()
    ->andReturn('return value');
  • Answer:
    預設 expects() 斷言只被呼叫一次, 相當於 once(), 若要斷言被呼叫多次, 可加入語法, 像是 twice()
以下的 Laravel example code 的意思是?
  • Example:
    <?php
    $mock = \Mockery::mock('MyClass');
    $mock->expects()
    ->name_of_method_1($arg1)
    ->andReturn('return value');
  • Answer:
    mock ‘MyClass’ object, 並斷言該 method 必須得被呼叫, 以及斷言 arg, 且定義 return value
    同 should()->once()->with()->andReturn()
以下的 Laravel example code 的意思是?
  • Example:
    <?php
    $mock = \Mockery::mock('MyClass');
    $mock->allows()
    ->name_of_method_1($arg1)
    ->andReturn('return value');
  • Answer:
    mock ‘MyClass’ object, 並斷言將被呼叫的 method, arg, 以及定義將 return 的 value, 至於 method 被呼叫幾次, 或者根本沒被呼叫都沒差
    同 shouldHave()->with() 語法
以下的 Laravel example code 的意思是?
  • Example:
    <?php
    $mock = \Mockery::mock('MyClass');
    $mock->allows([
    'name_of_method_1' => 'return value',
    'name_of_method_2' => 'return value',
    ]);
  • Answer:
    mock ‘MyClass’ object, 並斷言將被呼叫的 method 以及定義將 return 的 value, 至於 method 被呼叫幾次或者根本沒被呼叫都沒差
    同 shouldHave() 語法
以下的 Laravel example code 的意思是?
  • Example:
    <?php
    $mock = \Mockery::mock('MyClass');
    $mock->shouldReceive('foo')
    ->with(\Mockery::hasValue(value));

  • Answer:
    若 arg 為含有指定 value 的 array, 則符合 expectation
以下的 Laravel example code 的意思是?
  • Example:
    <?php
    $mock = \Mockery::mock('MyClass');
    $mock->shouldReceive('foo')
    ->with(\Mockery::hasKey(key));
  • Answer:
    若 arg 為含有指定 key 的 array, 則符合 expectation
以下的 Laravel example code 的意思是?
  • Example:
    <?php
    $mock = \Mockery::mock('MyClass');
    $mock->shouldReceive('foo')
    ->with(\Mockery::contains(value1, value2));
  • Answer:
    當 arg 為含有 value1, value2 的 array, 符合 expectation
以下的 Laravel example code 的意思是?
  • Example:
    <?php
    $mock = \Mockery::mock('MyClass');
    $mock->shouldReceive('foo')
    ->with(\Mockery::subset(array(0 => 'foo')));

  • Answer:
    若 arg 為含有 foo value 的 array, 則符合 expectation, key/value 都會被 compared
以下的 Laravel example code 的意思是?
  • Example:
    <?php
    $mock = \Mockery::mock('MyClass');
    $mock->shouldReceive('foo')
    ->with(\Mockery::notAnyOf(1, 2));

  • Answer:
    只要不符合 1 或 2, 就符合 args expectation
以下的 Laravel example code 的意思是?
  • Example:
    <?php
    $mock = \Mockery::mock('MyClass');
    $mock->shouldReceive('foo')
    ->with(\Mockery::anyOf(1, 2));

    // Hamcrest equivalent
    $mock->shouldReceive('foo')
    ->with(anyOf(1,2));

  • Answer:
    只要符合 1 或 2, 就符合 args expectation
以下的 Laravel example code 的意思是?
  • Example:
    <?php
    $mock = \Mockery::mock('MyClass');
    $mock->shouldReceive('foo')
    ->with(\Mockery::not(2));

    // Hamcrest equivalent
    $mock->shouldReceive('foo')
    ->with(not(2));
  • Answer:
    只要 arg 不是 2 就符合 args expectation
以下的 Laravel example code 的意思是?
  • Example:
    <?php
    $mock = \Mockery::mock('MyClass');
    $mock->shouldReceive("foo")
    ->with(\Mockery::capture($bar));
  • Answer:
    會將實際上 pass 到 foo() 的 arg captured 到 $bar variable, 然後可以在 test 中進一步的 assert $bar
以下的 Laravel example code 的意思是?
  • Example:
    <?php
    class MyClass
    {
    protected function foo()
    {
    }
    }

    $mock = \Mockery::mock('MyClass')
    ->shouldAllowMockingProtectedMethods();
    $mock->shouldReceive('foo');
  • Answer:
    使用 shouldAllowMockingProtectedMethods() 來 mock protected method
以下的 Laravel example code 的意思是?
  • Example:
    <?php
    $spy->shouldHaveReceived()
    ->foo('bar')
    ->twice();
  • Answer:
    斷言 method ‘foo’ with args ‘bar’ 會被呼叫 2 次
以下的 Laravel example code 的意思是?
  • Example:
    <?php
    $spy->shouldNotHaveReceived('foo', ['bar']);
  • Answer:
    斷言 foo method 不會被呼叫, 且 args 為 bar, args 可多個
以下的 Laravel example code 的意思是?
  • Example:
    <?php
    $spy->shouldHaveReceived('foo', ['bar']);
  • Answer:
    斷言 foo method 會被呼叫, 且 args 為 bar, args 可多個
以下的 Laravel example code 的意思是?
  • Example:
    <?php
    // Point.php
    <?php
    namespace App;

    class Point {
    public function setPoint($x, $y) {
    echo "Point (" . $x . ", " . $y . ")" . PHP_EOL;
    }
    }

    // Rectangle.php
    <?php
    namespace App;
    use App\Point;

    class Rectangle {
    public function create($x1, $y1, $x2, $y2) {
    $a = new Point();
    $a->setPoint($x1, $y1);

    $b = new Point();
    $b->setPoint($x2, $y1);

    $c = new Point();
    $c->setPoint($x2, $y2);

    $d = new Point();
    $d->setPoint($x1, $y2);

    $this->draw([$a, $b, $c, $d]);
    }

    public function draw($points) {
    echo "Do something with the points";
    }
    }

    // test class
    <?php
    class MyTest extends PHPUnit\Framework\TestCase {
    public function testCreate() {
    $point = Mockery::mock("App\Point");
    // check if our mock is called
    $point->shouldReceive("setPoint")->andThrow(Exception::class);

    $rect = Mockery::mock("App\Rectangle")->makePartial();
    $rect->shouldReceive("draw");

    // pass the App\Point mock into App\Rectangle as an alternative
    // to using new App\Point() in-place.
    $rect->shouldReceive("newPoint")->andReturn($point);

    $this->expectException(Exception::class);
    $rect->create(0, 0, 100, 100);
    Mockery::close();
    }
    }
  • Answer:
    建立一個 custom function 來封裝 new keyword, 然後可以 pass mock class 來取代 auto-loaded new class
以下的 Laravel example code 的意思是?
  • Example:
    <?php
    namespace AppTest;
    use Mockery as m;
    /**
    * @runTestsInSeparateProcesses
    * @preserveGlobalState disabled
    */
    class ServiceTest extends \PHPUnit_Framework_TestCase
    {
    public function testCallingExternalService()
    {
    $externalMock = m::mock('overload:App\Service\External');
    $externalMock->allows('sendSomething');
    $externalMock->shouldReceive('__construct')
    ->once()
    ->with(5);

    $service = new \App\Service();
    $result = $service->callExternalService($param);
    }
    }
  • Answer:
    test constructor argument
以下的 Laravel example code 的意思是?
  • Example:
    <?php
    \Mockery::getConfiguration()->enableReflectionCache();
    \Mockery::getConfiguration()->disableReflectionCache();
  • Answer:
    Mockery 大量的使用 reflection(), 所以會 cache, 但 cache 可能會產生一些問題。 如果出現 Error: Internal error: Failed to retrieve the reflection object, 可以把它關掉
以下的 Laravel example code 的意思是?
  • Example:
    <?php
    \Mockery::getConfiguration()->allowMockingNonExistentMethods(bool);
  • Answer:
    設定 Mockery, allow mock non-existent method
Laravel - Package - Telescope (官方文件原子化翻譯) Laravel - Digging Deeper - Localization (官方文件原子化翻譯筆記)

留言

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×