如何编写用于Laravel Artisan命令的PHPUnit测试,该命令调用外部API而不物理调用该API? [英] How to write a PHPUnit test for Laravel Artisan command that calls an external API without calling that API physically?

查看:143
本文介绍了如何编写用于Laravel Artisan命令的PHPUnit测试,该命令调用外部API而不物理调用该API?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

简要介绍,让您大致了解我想要实现的目标...

A brief introduction to give you an idea of what I want to achieve…

我有一个Laravel 5.6 artisan命令,该命令使用简单的GET请求调用外部API以获取一些数据.我想测试此而无需实际调用任何API . (我想脱机,但仍要进行绿色测试.)

I have a Laravel 5.6 artisan command that calls an external API with a simple GET request to get some data. I want to test this without actually calling any API physically. (I want to be offline and still have test test green).

现在简要说明逻辑的排列方式.

Now a brief explanation of how the logic is arranged.

1)此工匠命令(php artisan export:data)有自己的构造函数(__construct),在其中注入了很多东西.我注入的东西之一是ExportApiService类.容易.

1) This artisan command (php artisan export:data) has its own constructor (__construct) where I inject bunch of stuff. One of the things I inject is the ExportApiService class. Easy.

public function __construct(
    ExportApiService $exportApiService,
) {
    parent::__construct();

    $this->exportApiService = $exportApiService;
}

2)现在,ExportApiService扩展了abstract class AbstractApiService.在这个抽象类中,我构造了一个构造函数,在其中只需将GuzzleHttp\Client注入到$client属性中,以便在ExportApiService中可以使用$this->client调用API.容易.

2) Now ExportApiService extends abstract class AbstractApiService. Inside this abstract class I made a constructor where I simply inject GuzzleHttp\Client in a $client property so that in ExportApiService I can call API by using $this->client. Easy.

3)所以我的ExportApiService有一个称为exportData的方法.不重要的.有效.

3) So my ExportApiService has a method called exportData. Trivial. Works.

public function exportData(array $args = []): Collection
{
   $response = $this->client->request('GET', 'https://blahblah.blah');

   return collect(json_decode($response->getBody()->getContents(), true));
}

4)最后,在我的工匠命令中(我在第1点中介绍了),我称:

4) So finally in my artisan command (that I introduced in point no. 1) I call:

public function handle()
{
    $exportedData = $this->exportApiService->exportData($this->args);

    $this->info('Exported ' . count($exportedData) . ' records');
}

我要测试输出是否符合我的期望,完全不调用该外部API .我想以某种方式嘲笑它……

I want to test if the output matches my expectations without calling that external API at all. I want to mock it somehow…

public function testExportSuccessful()
{
    $this->console->call('export:data', [$some_arguments]);

    $output = $this->console->output();

    $this->assertContains('Exported 123 records', $output); // this does not work :(
}

现在我的确切问题是-我如何在artisan命令每次调用exportData()时强制Laravel/PHPUnit返回一个固定值?

Now my exact question - how can I force Laravel / PHPUnit to return a fixed value every time the artisan command will call exportData()?

您尝试了什么?

What did you try?

我尝试使用以下代码创建setUp()方法:

I tried creating a setUp() method with the following code:

public function setUp()
{
    parent::setUp();

    $mock = $this->createMock(ExportApiService::class);

    $mock->method('exportData')->willReturn(123); // give me a dummy integer each time exportData is being called so that I can use is in the assert at the end
}

但这根本不起作用,但是对我来说很有意义.

But this does not work at all however it makes sense to me.

谢谢您的帮助.

推荐答案

您创建了一个模拟对象,但没有将其绑定到容器中.没有绑定,Laravel运行命令时,它将仅生成一个新的ExportApiService实例.

You created a mocked object, but you didn't bind it into the container. Without binding, when Laravel runs your command, it will just generate a new ExportApiService instance.

public function setUp()
{
    parent::setUp();

    $mock = $this->createMock(ExportApiService::class);

    $mock->method('exportData')->willReturn(123);

    // bind the mock in the container, so whenever you ask for
    // a new ExportApiService, you'll get your mocked object.
    $this->app->instance(ExportApiService::class, $mock);
}


您还有一个选择是模拟您的Guzzle请求,而不是这样做.这样,您的所有代码都会像往常一样执行,但是当您进行API调用时,Guzzle会返回预定的响应,而不是实际进行调用.您可以在此处找到关于测试的钳制文档.

在使用模拟响应配置客户端之后,可以将该客户端实例绑定到容器中,以便在创建ExportApiService时,Laravel会向您设置的客户端注入模拟响应.

After you configure your client with the mocked responses, you would bind that client instance into the container, so that when your ExportApiService is created, Laravel injects the client you've setup with the mocked responses.

这篇关于如何编写用于Laravel Artisan命令的PHPUnit测试,该命令调用外部API而不物理调用该API?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆