テストシミュレーターのモック化


##イベント シミュレーション

    ##スコープ指定イベント シミュレーション
  • # #メールシミュレーション
  • 通知シミュレーション
  • キューシミュレーション
    • ストレージシミュレーション
    • ファサード
  • ##

    はじめに

    Laravel アプリケーションをテストするとき、アプリケーションの特定の機能の動作を「シミュレート」して、その部分がテストで実際に実行されないようにしたい場合があります。例: コントローラーの実行中にイベント (Event) がトリガーされるため、コントローラーのテスト時にイベントが実際に実行されなくなります。これにより、イベントのトリガーについて心配することなく、コントローラーの HTTP 応答のみをテストできます。もちろん、このイベント ロジックを別のテストでテストすることもできます。

    Laravel は、イベント、タスク、ファサードのシミュレーションのためのすぐに使えるヘルパー関数を提供します。これらの関数は Mocker に基づいてカプセル化されており、非常に使いやすく、複雑な Mockery 関数を手動で呼び出す必要はありません。もちろん、Mockery を使用したり、PHPUnit を使用して独自のエミュレータを作成することもできます。

    オブジェクトのモック

    Laravel のサービス コンテナを通じてアプリケーションに挿入されるオブジェクトをモックする場合、次のようにします。モック インスタンスは、instance としてコンテナにバインドする必要があります。これにより、実際のオブジェクトを構築する代わりに、オブジェクトのモック インスタンスを使用するようにコンテナに指示されます。

    use Mockery;
    use App\Service;
    $this->instance(Service::class, Mockery::mock(Service::class, function ($mock) {
        $mock->shouldReceive('process')->once();
       })
    );

    上記のプロセスをより便利にするために、Laravel の mock メソッドを使用できます。基本テスト ケース クラス :

    use App\Service;$this->mock(Service::class, function ($mock) {
        $mock->shouldReceive('process')->once();
     });

    タスク シミュレーション

    シミュレーションの代わりに、 を使用できます。 Bus Facade の fake メソッドは、タスクが実際に実行のために分散されるのを防ぎます。フェイクを使用する場合、通常、アサーションはテスト コードの背後に表示されます。

    <?php
        namespace Tests\Feature;
        use Tests\TestCase;use App\Jobs\ShipOrder;
        use Illuminate\Support\Facades\Bus;
        use Illuminate\Foundation\Testing\RefreshDatabase;
        use Illuminate\Foundation\Testing\WithoutMiddleware;
        class ExampleTest extends TestCase{
            public function testOrderShipping()
                {   
                     Bus::fake();        
                     // 执行订单发货...        
                     Bus::assertDispatched(ShipOrder::class, function ($job) use ($order) { 
                                return $job->order->id === $order->id;      
                                 });       
                      // 断言任务并未分发...        
                      Bus::assertNotDispatched(AnotherJob::class);   
                    }
               }

    イベント シミュレーション

    モックとしてEvent ファサードの fake メソッドを使用して、イベント リスナーをシミュレートできます。イベント リスナーは、テスト中に実際にはトリガーされません。その後、実行中のアサーション イベントをテストし、受信したデータを検査することもできます。フェイクを使用する場合、通常、アサーションはテスト コードの後ろに表示されます。

    <?php
        namespace Tests\Feature;
        use Tests\TestCase;use App\Events\OrderShipped;
        use App\Events\OrderFailedToShip;
        use Illuminate\Support\Facades\Event;
        use Illuminate\Foundation\Testing\RefreshDatabase;
        use Illuminate\Foundation\Testing\WithoutMiddleware;
        class ExampleTest extends TestCase{   
         /**
         * 测试订单发送
         */   
          public function testOrderShipping() 
             {   
                  Event::fake();        
                  // 执行订单发送...        
                  Event::assertDispatched(OrderShipped::class, function ($e) use ($order) {  
                            return $e->order->id === $order->id;    
                         });        
                   // 断言一个事件被发送了两次...   
                  Event::assertDispatched(OrderShipped::class, 2);        
                  // 未分配断言事件...        
                  Event::assertNotDispatched(OrderFailedToShip::class);   
                }
            }

    {note} Event::fake() を呼び出した後は、イベント監視は実行されません。したがって、イベントベースのテストではファクトリ モデルを使用する必要があります。たとえば、モデルの creating イベントで UUID を作成するには、Event::fake() を呼び出す必要があります。 after 工場出荷時のモデルを使用します。

    イベントのサブセットのシミュレート

    特定のイベント セットのイベント リスナーのみをシミュレートしたい場合は、それらを fake に渡すことができます。 または fakeFor メソッド:

    /**
     * 测试订单流程
     */
     public function testOrderProcess(){ 
        Event::fake([   
             OrderCreated::class,   
             ]);    
        $order = factory(Order::class)->create();    
        Event::assertDispatched(OrderCreated::class);    
       // 其他事件照常发送...    
      $order->update([...]);
     }

    スコープ指定イベント シミュレーション

    If ifテストの一部についてのみイベント リスニングをシミュレートしたい場合は、fakeFor メソッドを使用できます:

    <?php
        namespace Tests\Feature;
        use App\Order;use Tests\TestCase;
        use App\Events\OrderCreated;
        use Illuminate\Support\Facades\Event;
        use Illuminate\Foundation\Testing\RefreshDatabase;
        use Illuminate\Foundation\Testing\WithoutMiddleware;
        class ExampleTest extends TestCase{   
         /**
         * 测试订单流程
         */   
         public function testOrderProcess()   
          {     
             $order = Event::fakeFor(function () { 
                        $order = factory(Order::class)->create();            
                        Event::assertDispatched(OrderCreated::class);            
                        return $order;        
                 });       
               // 事件按正常方式发送,观察者将运行...       
              $order->update([...]);    
            }
          }

    メール シミュレーション

    Mail Facade の fake メソッドを使用して、電子メール送信をシミュレートできます。テスト中は電子メールは実際には送信されません。 Mailable がユーザーに送信されたことを主張でき、ユーザーは受信した内容を確認することもできます。フェイクを使用する場合、アサーションは通常、テスト コードの後に​​配置されます。

    <?php
        namespace Tests\Feature;
        use Tests\TestCase;use App\Mail\OrderShipped;
        use Illuminate\Support\Facades\Mail;
        use Illuminate\Foundation\Testing\RefreshDatabase;
        use Illuminate\Foundation\Testing\WithoutMiddleware;
        class ExampleTest extends TestCase{ 
           public function testOrderShipping()  
             {     
                Mail::fake();        
                // 断言没有发送任何邮件...        
                Mail::assertNothingSent();        
                // 执行订单发送...        
                Mail::assertSent(OrderShipped::class, function ($mail) use ($order) {  
                          return $mail->order->id === $order->id;       
                       });        
               // 断言一条发送给用户的消息...        
               Mail::assertSent(OrderShipped::class, function ($mail) use ($user) { 
                          return $mail->hasTo($user->email) &&                   
                          $mail->hasCc('...') &&                   
                          $mail->hasBcc('...');     
                       });        
                 // 断言邮件被发送两次...     
               Mail::assertSent(OrderShipped::class, 2);       
               // 断言没有发送邮件...        
               Mail::assertNotSent(AnotherMailable::class);   
               }
            }

    バックグラウンド タスクを使用してメール送信キューを実行する場合は、assertSent# の代わりに assertQueued を使用する必要があります。 ##:

    Mail::assertQueued(...);
    Mail::assertNotQueued(...);

    通知シミュレーション

    Notification ファサードの を使用できます。 fake 通知の送信をシミュレートするメソッド。テスト中は実際には通知は送信されません。その後、通知がユーザーに送信されたことを主張し、受信した内容を検査することもできます。フェイクを使用する場合、アサーションは通常、テスト コードの後に​​配置されます。

    <?php
        namespace Tests\Feature;
        use Tests\TestCase;
        use App\Notifications\OrderShipped;
        use Illuminate\Support\Facades\Notification;
        use Illuminate\Notifications\AnonymousNotifiable;
        use Illuminate\Foundation\Testing\RefreshDatabase;
        use Illuminate\Foundation\Testing\WithoutMiddleware;
        class ExampleTest extends TestCase{
            public function testOrderShipping()
                {   
                     Notification::fake();        
                     // 断言没有发送通知...        
                     Notification::assertNothingSent();        
                     // 执行订单发送...        
                     Notification::assertSentTo(          
                       $user,            
                       OrderShipped::class,            
                       function ($notification, $channels) use ($order) {    
                                   return $notification->order->id === $order->id;   
                                      }       
                            );       
                       // 断言向给定用户发送了通知...      
                      Notification::assertSentTo(     
                            [$user], OrderShipped::class  
                              );       
                       // 断言没有发送通知...   
                      Notification::assertNotSentTo( 
                            [$user], AnotherNotification::class    
                              );       
                      // 断言通过 Notification::route() 方法发送通知...        
                       Notification::assertSentTo(     
                              new AnonymousNotifiable, OrderShipped::class     
                                );   
                          }
                 }

    ##キュー シミュレーション

    シミュレーションの代替として、

    Queue

    ファサードの fake メソッドを使用すると、実際にタスクを実行キューに入れることを回避できます。その後、タスクがキューにプッシュされたことをアサートし、受信したデータを検査することもできます。フェイクを使用する場合、通常、アサーションはテスト コードの後に​​配置されます。

    <?php
        namespace Tests\Feature;
        use Tests\TestCase;use App\Jobs\ShipOrder;
        use Illuminate\Support\Facades\Queue;
        use Illuminate\Foundation\Testing\RefreshDatabase;
        use Illuminate\Foundation\Testing\WithoutMiddleware;
        class ExampleTest extends TestCase{
            public function testOrderShipping() 
               {   
                    Queue::fake();        
                    // 断言没有任务被发送...        
                    Queue::assertNothingPushed();        
                    // 执行订单发送...        
                    Queue::assertPushed(ShipOrder::class, function ($job) use ($order) {  
                              return $job->order->id === $order->id;       
                             });        
                    // 断言任务进入了指定队列...        
                    Queue::assertPushedOn('queue-name', ShipOrder::class); 
                    // 断言任务进入2次...        
                      Queue::assertPushed(ShipOrder::class, 2);        
                      // 断言没有一个任务进入队列...        
                      Queue::assertNotPushed(AnotherJob::class);        
                      // 断言任务是由特定的通道发送的...        
                      Queue::assertPushedWithChain(ShipOrder::class, [    
                              AnotherJob::class,            
                              FinalJob::class        
                           ]);  
                       }
                   }

    ##ストレージ シミュレーション
    使用できます

    Storage

    Facade の

    fake メソッドは、模擬ディスクを簡単に生成でき、UploadedFile クラスのファイル生成ツールと組み合わせることで、ファイルのアップロード テストを大幅に簡素化します。例:

    <?php
        namespace Tests\Feature;
        use Tests\TestCase;
        use Illuminate\Http\UploadedFile;
        use Illuminate\Support\Facades\Storage;
        use Illuminate\Foundation\Testing\RefreshDatabase;
        use Illuminate\Foundation\Testing\WithoutMiddleware;
        class ExampleTest extends TestCase{
            public function testAvatarUpload() 
               {   
                    Storage::fake('avatars');        
                    $response = $this->json('POST', '/avatar', [ 
                               'avatar' => UploadedFile::fake()->image('avatar.jpg')     
                  ]);        
              // 断言文件已存储...        
              Storage::disk('avatars')->assertExists('avatar.jpg');        
              // 断言文件不存在...        
              Storage::disk('avatars')->assertMissing('missing.jpg');   
              }
           }
    {tip} デフォルトでは、

    fake
    メソッドは一時ディレクトリ内のすべてのファイルを削除します。これらのファイルを保存したい場合は、「persistentFake」を使用できます。

    ファサード

    従来の静的メソッド呼び出しとは異なり、ファサードもシミュレートできます。従来の静的手法と比べて大きな利点があり、依存性注入を使用してもテスト容易性は半分も劣りません。テストでは、コントローラー内の Laravel Facade への呼び出しをシミュレートすることができます。たとえば、次のコントローラの動作:

    <?php
        namespace App\Http\Controllers;
        use Illuminate\Support\Facades\Cache;
        class UserController extends Controller{   
         /**
         * 显示应用里所有用户
         *
         * @return Response
         */    
         public function index() 
            {      
              $value = Cache::get('key');      
                //
             }
         }

    ShouldReceive メソッドを通じて Cache ファサードをシミュレートできます。この関数は Mockery# を返します。 ## 実例。 。 Facade 呼び出しは実際には Laravel のサービス コンテナによって管理されるため、Facade は従来の静的クラスよりも優れたテスト容易性を示すことができます。次に、Cache ファサードの get メソッドをシミュレートしましょう:

    <?php
        namespace Tests\Feature;
        use Tests\TestCase;
        use Illuminate\Support\Facades\Cache;
        use Illuminate\Foundation\Testing\RefreshDatabase;
        use Illuminate\Foundation\Testing\WithoutMiddleware;
        class UserControllerTest extends TestCase{ 
           public function testGetIndex()  
             {    
                 Cache::shouldReceive('get')              
                       ->once()                    
                       ->with('key')                    
                       ->andReturn('value');        
                 $response = $this->get('/users');      
                 // ...  
                }
           }

    {note}

    Request ファサードをシミュレートすることはできません。テストの実行時に特定のパラメーターを渡す必要がある場合は、代わりに、getpost などの HTTP ヘルパー関数を使用してください。同様に、テスト中に Config::set を呼び出して、Config ファサードをシミュレートしてください。

    この記事は、