教程 > laravel 教程 > 阅读:29

laravel 模拟——迹忆客-ag捕鱼王app官网

简介

测试 laravel 应用的时候,你可能还想要“ 模拟 ”应用的特定状态,以便在测试中不让它们真的执行。例如,测试触发事件的控制器时,你可能想要模拟事件监听器以便它们不在测试期间真的执行。这样的话你就可以只测试控制器的 http 响应,而不必担心事件监听器的执行,因为事件监听器可以在它们自己的测试用例中被测试。

laravel 为模拟事件、任务以及 facade 提供了辅助函数,这些辅助函数主要是在 mockery 之上提供了一个方便的层这样你就不必手动调用复杂的 mockery 方法。当然,我们也可以使用 mockeryphpunit 来创建自己的模拟。


模拟对象

模拟对象可以通过 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();
});

当我们只需要模拟对象的几个方法时,您可以使用partialmock方法。未被模拟的方法在调用时会正常执行:

use app\service;
$this->partialmock(service::class, function ($mock) {
    $mock->shouldreceive('process')->once();
});

类似的,如果想要暗中监控某个对象,laravel 测试基类还提供了 spy 方法,该方法提供了对 mockery::spy 方法的封装:

use app\service;
$this->spy(service::class, function ($mock) {
    $mock->shouldhavereceived('process');
});

伪造 bus

作为模拟的替代方案,你可以使用 bus facade 的 fake 方法来阻止任务被分发,使用 fake 的时候,测试代码执行后会进行断言:

order->id === $order->id;
        });
                
        // assert a job was not dispatched...
        bus::assertnotdispatched(anotherjob::class);
    }
}

伪造事件

作为模拟的替代方案,我们可以使用 event facade 的 fake 方法来阻止事件监听器被执行,然后断言事件被分发,甚至检查接收的数据。使用 fake 方法时,测试代码执行后会进行断言:

order->id === $order->id;
        });
        // assert an event was dispatched twice...
        event::assertdispatched(ordershipped::class, 2);
        // assert an event was not dispatched...
        event::assertnotdispatched(orderfailedtoship::class);
    }
}

注:调用 event:fake() 后,事件监听器不会执行,因此,如果你的测试使用了依赖于事件的模型工厂,例如在模型 creating 事件中创建一个 uuid,那么你需要在使用工厂后再调用 event::fake()。

伪造事件子集

如果只想要为指定的事件集合伪造事件监听器,可以将它们传递到 fakefakefor 方法:

/**
 * test order process.
 */
public function testorderprocess()
{
    event::fake([
        ordercreated::class,
    ]);
    $order = factory(order::class)->create();
    event::assertdispatched(ordercreated::class);
    // other events are dispatched as normal...
    $order->update([...]);
}

有作用域的事件伪造

如果只想为部分测试伪造事件监听器,可以使用 fakefor 方法:

create();
            event::assertdispatched(ordercreated::class);
            return $order;
        });
        // events are dispatched as normal and observers will run ...
        $order->update([...]);
    }
}

伪造邮件

我们可以使用 mail facade 的 fake 方法阻止邮件发送,然后断言发送给用户的可邮寄类,甚至检查接收的数据。使用 fake 的时候,断言会在测试代码执行后进行:

order->id === $order->id;
        });
        // assert a message was sent to the given users...
        mail::assertsent(ordershipped::class, function ($mail) use ($user) {
            return $mail->hasto($user->email) &&
                   $mail->hascc('...') &&
                   $mail->hasbcc('...');
        });
        // assert a mailable was sent twice...
        mail::assertsent(ordershipped::class, 2);
        // assert a mailable was not sent...
        mail::assertnotsent(anothermailable::class);
    }
}

如果将邮件发送推送到了后台异步队列,需要使用 assertqueued 来替代 assertsent

mail::assertqueued(...);
mail::assertnotqueued(...);

伪造通知

你可以使用 notification 门面的 fake 方法来阻止通知被发送,之后断言通知是否被发送给用户,甚至可以检查接收的数据。使用 fake 的时候,断言会在测试代码执行后进行:

order->id === $order->id;
            }
        );
        // assert a notification was sent to the given users...
        notification::assertsentto(
            [$user], ordershipped::class
        );
        // assert a notification was not sent...
        notification::assertnotsentto(
            [$user], anothernotification::class
        );
        // assert a notification was sent via notification::route() method...
        notification::assertsentto(
            new anonymousnotifiable, ordershipped::class
        );
        // assert notification::route() method sent notification to the correct user...
        notification::assertsentto(
            new anonymousnotifiable,
            ordershipped::class,
            function ($notification, $channels, $notifiable) use ($user) {
                return $notifiable->routes['mail'] === $user->email;
            }
        );
    }
}

伪造队列

作为模拟的替代方案,可以使用 queue facadefake 方法来阻止任务被推动到队列,然后断言任务是否被推送到队列,甚至检查接收的数据。使用 fake 的时候,断言会在测试代码执行后进行:

order->id === $order->id;
        });
        // assert a job was pushed to a given queue...
        queue::assertpushedon('queue-name', shiporder::class);
        // assert a job was pushed twice...
        queue::assertpushed(shiporder::class, 2);
        // assert a job was not pushed...
        queue::assertnotpushed(anotherjob::class);
        // assert a job was pushed with a given chain of jobs, matching by class...
        queue::assertpushedwithchain(shiporder::class, [
            anotherjob::class,
            finaljob::class
        ]);
        // assert a job was pushed with a given chain of jobs, matching by both class and properties...
        queue::assertpushedwithchain(shiporder::class, [
            new anotherjob('foo'),
            new finaljob('bar'),
        ]);
        // assert a job was pushed without a chain of jobs...
        queue::assertpushedwithoutchain(shiporder::class);
    }
}

伪造存储

storage facadefake 方法允许我们轻松构造伪造硬盘,以及使用uploadedfile 类生成的文件,从而极大简化了文件上传测试,例如:

json('post', '/photos', [
            uploadedfile::fake()->image('photo1.jpg'),
            uploadedfile::fake()->image('photo2.jpg')
        ]);
        // assert one or more files were stored...
        storage::disk('photos')->assertexists('photo1.jpg');
        storage::disk('photos')->assertexists(['photo1.jpg', 'photo2.jpg']);
        // assert one or more files were not stored...
        storage::disk('photos')->assertmissing('missing.jpg');
        storage::disk('photos')->assertmissing(['missing.jpg', 'non-existing.jpg']);
    }
}

注:默认情况下,fake 方法会删除临时目录下的所有文件,如果你想要保留这些文件,可以使用 persistentfake 方法。


facade

不同于传统的静态方法调用,facade 可以被模拟。这与传统静态方法相比是一个巨大的优势,并且你可以对依赖注入进行测试。测试的时候,你可能经常想要在控制器中模拟 laravel facade 的调用,例如,看看下面的控制器动作:

我们可以通过使用 shouldreceive 方法模拟 cache facade的调用,该方法返回一个mockery模拟的实例,由于facade通过 laravel 服务容器进行解析和管理,所以它们比通常的静态类更具有可测试性。例如,我们可以来模拟 cache facade get 方法的调用:

once()
                    ->with('key')
                    ->andreturn('value');
        $response = $this->get('/users');
        // ...
    }
}

注:不要模拟 request facade,取而代之地,可以在测试时传递期望输入到 http 辅助函数如 getpost,类似地,也不要模拟 config facade,在测试中调用 config::set 方法即可。

查看笔记

扫码一下
查看教程更方便
网站地图