Преамбула: я разрабатываю с 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));
}
Теперь, мои сомнения.
Я пишу API, которыйвызывает метод gateway
fetchPublicIp
.
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
?
Еще одна идея, которую я получил, - перенести зависимость из метода в __construct()
контроллера, но проблема та же: как макетировать только конструктор для контроллера?
Псевдокод:
$mock = new Mock('Ipify\Ip');
$public_ip_controller = new PublicIpController($gateway, $mock)
$response = $this->get(Route('public_ip_update'));