Laravel / PHPUnit: как издеваться над параметром для метода (или для самого контроллера конструктора)?

#laravel #mocking #phpunit

#laravel #издевательство #phpunit

Вопрос:

Преамбула: я разрабатываю с использованием Laravel 5.7 и шаблона репозитория / шлюза.

Используя внедрение зависимостей, я могу издеваться и тестировать свои собственные классы, на самом деле не завися от внешней библиотеки.

Это метод подчеркивания:

 /**
     * @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('IpifyIp');

        $mock->shouldReceive('get')
            ->andReturn($this->faker->ipv4())
            ->mock();

        $this->assertTrue(class_exists('IpifyIp'));
        $this->assertTrue($mock instanceof Ip);
        $gateway = $this->app->make('AppGatewaysPublicIPGateway');
        $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 IlluminateHttpJsonResponse
     */
    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('IpifyIp');
$public_ip_controller = new PublicIpController($gateway, $mock)
$response = $this->get(Route('public_ip_update'));