序言:我正在使用Laravel 5.7和Repository / Gateway模式进行开发。
使用依赖注入,我可以模拟和测试自己的类,而无需真正依赖外部库。
这是下划线方法:
/**
* @param Ip $ip
* @return string
* @throws ConnectionError
* @throws ServiceError
*/
public function fetchPublicIp(Ip $ip)
{
try {
$public_ip = $ip::get();
return $public_ip;
} catch (ConnectionError $e) {
// If you get here, it means you were unable to reach the ipify service,
// most likely because of a network error on your end.
//echo $e->getMessage();
//return $e;
throw new ConnectionError();
} catch (ServiceError $e) {
// If you get here, it means ipify is having issues, so the request
// couldn't be completed :(
throw new ServiceError();
} catch (\Exception $e) {
// Something else happened (non-ipify related).
throw new \Exception();
}
}
实际上,这是经过充分测试的
/**
* READ (external)
* Test that we can get external public IP
*
* @return void
*/
public function test_can_get_public_ip()
{
$this->withoutExceptionHandling();
$mock = Mockery::mock('Ipify\Ip');
$mock->shouldReceive('get')
->andReturn($this->faker->ipv4())
->mock();
$this->assertTrue(class_exists('Ipify\Ip'));
$this->assertTrue($mock instanceof Ip);
$gateway = $this->app->make('App\Gateways\PublicIPGateway');
$public_ip = $gateway->fetchPublicIp($mock);
$this->assertIsString(filter_var($public_ip, FILTER_VALIDATE_IP));
}
现在,我的疑问。
我正在编写一个调用gateway
方法fetchPublicIp
的API。
PubliIpApiController.php
/**
* Update the Public Ip stored in database
*
* @return \Illuminate\Http\JsonResponse
*/
public function update(Ip $ipify)
{
$public_ip = $this->getGateway()->fetchPublicIp($ipify);
// other stuffes here
return response()->json([
'public_ip' => $public_ip
]);
}
但是,我们处于起点。我可以直接模拟外部update
类来测试Ip
方法。
但是,如何直接测试我自己的API调用?
存根测试是
<?php
[...]
$response = $this->get(Route('public_ip_update'));
[...]
?>
但是,当然,通过这个电话,我真的(新)耦合到了外部IP。
那么,如何模拟Ip
外部类以将模拟作为参数传递给updatePublicIp
?
我得到的另一个想法是将依赖关系从方法移至Controller的__construct()
,但是问题是相同的:如何仅模拟控制器的构造函数?
伪代码:
$mock = new Mock('Ipify\Ip');
$public_ip_controller = new PublicIpController($gateway, $mock)
$response = $this->get(Route('public_ip_update'));