规划好了APN provider的路由之后,这一节,我们就用TDD的方式逐一实现它们。

作为开始,我们用最简单的两个API来演示一个完整的TDD过程,通过这个过程来体会测试用例是如何“驱动”开发过程的。听着好像挺高级,其实核心的想法很简单:先假定功能已经开发好了,然后直接编写测试用例。显然,此时的测试是无法通过的。而这个驱动的过程,就是不断完善代码,最终让测试得以通过的过程。

定义API的细节

直接来看例子,我们将要实现的两个API是:

GET /api/v1/public-key/version
GET /api/v1/public-key

这两个API都不需要传递参数,服务器直接返回JSON包含对应请求的资源。其中,version的返回值是这样的:

{
  'version': 1
}

public-key的返回值是这样的(这里,用xxxxxxxxxxxxxxx替代了返回的公钥):

{
  'public': 'xxxxxxxxxxxxxxxx',
  'version': 1
}

以上,就是这两个API的返回值细节。接下来,假设它们已经实现完了,我们要为它们编写测试用例。

设置phpunit

开始之前,要先设置一下执行单元测试的phpunit。Laravel在项目的根目录中添加了一个phpunit.xml文件,在这个文件中找到php节点,在其中添加下面两行内容:

<server name="DB_CONNECTION" value="sqlite"/>
<server name="DB_DATABASE" value=":memory:"/>

它们表示在单元测试执行的时候使用内存中的sqlite数据库,取代开发环境中的MySQL。这样做是因为在测试的过程中可能会频繁的重置数据库中的内容,但我们并不希望这些操作影响到开发环境中使用的数据库。

从编写测试用例开始

设置好之后,作为TDD的开始,我们直接为这两个API编写测试用例。核心思路非常简单:请求API并检查返回值就好了。为此,在项目的根目录,先执行下面的命令创建测试文件:

php artisan make:test PublicKeyTest

在Laravel的tests目录里,有两个子目录,其中:

  • Feature用于存放某个功能的测试用例,例如将要实现的API。当我们执行了上面的命令之后,在Feature目录中就会包含一个PublicKeyTest.php文件,对/public-key这个API的测试,就都写在这里;
  • Unit存放更小粒度的单元测试,例如某个函数。为了把生成的测试用例放到这个目录,在make:test的时候,加上--unit就好了,稍后,我们开发向APN发送数据的功能时,就会把处理数据的测试用例放到这里;

现在,打开刚创建的PublicKeyTest.php,在它包含的PublicKeyTest类中,自带了一个testExample测试用例:

<?php

namespace Tests\Feature;

use Tests\TestCase;
use Illuminate\Foundation\Testing\WithFaker;
use Illuminate\Foundation\Testing\RefreshDatabase;

class PublicKeyTest extends TestCase
{
    /**
     * A basic feature test example.
     *
     * @return void
     */
    public function testExample()
    {
        $response = $this->get('/');

        $response->assertStatus(200);
    }
}

在phpunit里,所有用test开头方法,都是测试用例。从这个默认的测试用例中,我们能发现不少有用的东西。例如,为了发起一个API请求,直接用$this->get()就好了,其实,Laravel还支持post / put / patch / delete方法。另外,为了检测HTTP API返回的状态码,可以通过assertStatus(200)实现。说到这,似乎测试GET /api/v1/public-key/version这个API就没任何问题了。

我们把之前的testExample改造成这样:

public function testGetPublicKeyVersion()
{
  $response = $this->get('/api/v1/public-key/version');
  $data = $response->decodeResponseJson();

  $this->assertEquals($data['version'], 1);
  $response->assertStatus(200);
}

可以看到,除了检查返回的status code之外,我们还用assertEquals检查了返回JSON中的version字段的值。这样,第一个测试用例就完成了。现在,登录到php容器,在项目的根目录执行./vendor/bin/phpunit。emm...

如果没有意外,显然测试会失败的,因为处理这个路由的KeyController@getPublicKeyVersion现在还是一个空方法。于是,接下来的任务就变成了,让这个测试用例通过测试。

要注意的是,我们的目标仅仅是通过测试而已,不要给这个目标附加任何额外的要素,于是,第一版的getPublicKeyVersion只要这样貌似就可以了:

public function getPublicKeyVersion()
{
  return response()->json([
    'version' => 1
  ]);
}

What's next?

虽然getPublicKeyVersion看着有点儿糊弄事儿,但这个方法的确可以帮助我们通过测试。也就是说,我们编写的测试用例,只能“驱动”出来这么一个糊弄事儿的版本。因此,问题的源头,还要追溯到一开始我们编写的测试用例上。理解了这个围绕着测试用例去编写代码的想法之后,下段视频里,我们就来改进这个测试驱动开发的过程。

所有订阅均支持 12 期免息分期

¥ 59

按月订阅

一个月,观看并下载所有视频内容。初来泊学,这可能是个最好的开始。

开始订阅

¥ 512

按年订阅

一年的时间,让我们一起疯狂地狩猎知识吧。比按月订阅优惠 28%

开始订阅

¥ 1280

泊学终身会员

永久观看和下载所有泊学网站视频,并赠送 100 元商店优惠券。

我要加入
如需帮助,欢迎通过以下方式联系我们