LaravelCollections。有某种 assertStructure 方法吗?

Laravel Collections. Is there some kind of assertStructure method?

我正在编写测试,我想断言,返回的 collection 具有一些特定的结构。

为了断言 jsons,我在 Responce object 上使用了 assertJsonStructure() 方法。

我还没有找到 \Illuminate\Support\Collection 的类似内容。我是不是错过了一些 package/framework 方法。

我想要什么的例子

$collection = collect([
    'name'      => 'John',
    'surname'   => 'Smith',
    'birthoday' => [
        'day'   => 23,
        'month' => 5,
        'year'  => 1970,
    ],
]);

$collection->assertStructure([          //true
    'name',
    'surname',
    'birthday' => ['day', 'month', 'year'],
]);

我会接受

no

也是一个答案,但如果它是如何验证这种嵌套的示例 collection。

答案是,您可以在API documentation, there is no method at the namespace Illuminate\Support\Collection which makes what you are looking for. (You can find Laravel assertive method here)

中简单地寻找自信的laravel方法

作为一个可行的替代方案,您为什么不直接序列化您的集合并使用 assertJsonStructure() 方法检查它?

您可以使用 response() 助手来填充 Illuminate/Foundation/Testing/TestResponse:

use Illuminate/Foundation/Testing/TestResponse;

$testResponse = new TestResponse(response()->json($collection->toArray());
return $testResponse->assertJsonStructure([
    'name',
    'surname',
    'birthday' => ['day', 'month', 'year'],
]);

我是如何找到这个解决方案的:

  • 您需要与 returns 测试中的方法 $this->json() 完全相同的对象,它来自特征 MakesHttpRequests right here.
  • 正如方法注释所指定的,它returns一个Illuminate\Foundation\Testing\TestResponse
  • 寻找构造函数 at the docs,看看它需要什么,一个通用的响应对象,Illuminate/Http/Response

希望对您有所帮助。

Collection 实例上没有这样的函数,最接近的是:

  • 检查它是否有 has()
  • 的密钥
  • contains()
  • 检查它是否包含一些值
  • 还有其他方法可以检查是否存在某些东西,但是

如果你需要灵感,可以通过Laravel在/Illuminate/Foundation/Testing/TestResponse.php中实现assertJsonStructure()的方式获得:

/**
 * Assert that the response has a given JSON structure.
 *
 * @param  array|null  $structure
 * @param  array|null  $responseData
 * @return $this
 */
public function assertJsonStructure(array $structure = null, $responseData = null)
{
    if (is_null($structure)) {
        return $this->assertJson($this->json());
    }

    if (is_null($responseData)) {
        $responseData = $this->decodeResponseJson();
    }

    foreach ($structure as $key => $value) {
        if (is_array($value) && $key === '*') {
            PHPUnit::assertInternalType('array', $responseData);

            foreach ($responseData as $responseDataItem) {
                $this->assertJsonStructure($structure['*'], $responseDataItem);
            }
        } elseif (is_array($value)) {
            PHPUnit::assertArrayHasKey($key, $responseData);

            $this->assertJsonStructure($structure[$key], $responseData[$key]);
        } else {
            PHPUnit::assertArrayHasKey($value, $responseData);
        }
    }

    return $this;
}

如您所见,如果存在子结构,则有一个递归调用来检查结构。

更新:

作为解决您问题的基本测试,我将 assertJsonStructure() 修改为 assertArrayStructure() 并且此工作测试:

/**
 * A basic test example.
 *
 * @return void
 */
public function testBasicTest()
{
    $collect = collect(['name' => '1', 'detail' => ['age' => 1,'class' => 'abc']]);

    $this->assertArrayStructure(['name', 'detail' => ['class', 'age']], $collect->toArray());
}


/**
 * Assert the array has a given structure.
 *
 * @param  array  $structure
 * @param  array  $arrayData
 * @return $this
 */
public function assertArrayStructure(array $structure, array $arrayData)
{
    foreach ($structure as $key => $value) {
        if (is_array($value) && $key === '*') {
            $this->assertInternalType('array', $arrayData);

            foreach ($arrayData as $arrayDataItem) {
                $this->assertArrayStructure($structure['*'], $arrayDataItem);
            }
        } elseif (is_array($value)) {
            $this->assertArrayHasKey($key, $arrayData);

            $this->assertArrayStructure($structure[$key], $arrayData[$key]);
        } else {
            $this->assertArrayHasKey($value, $arrayData);
        }
    }

    return $this;
}

从 Laravel 8.x 开始,其他答案有些过时了。您可以使用 AssertableJsonString,因为 TestResponse 在后台使用它:

(new \Illuminate\Testing\AssertableJsonString($yourJson))->assertStructure($yourStructure);