定制 viewtrender/php-youtube-testkit-core 二次开发

按需修改功能、优化性能、对接业务系统,提供一站式技术支持

邮箱:yvsm@zunyunkeji.com | QQ:316430983 | 微信:yvsm316

viewtrender/php-youtube-testkit-core

Composer 安装命令:

composer require viewtrender/php-youtube-testkit-core

包简介

Core mock layer for Google YouTube APIs

README 文档

README

Fake responses for YouTube Data API, Analytics API, and Reporting API in PHP tests.

Tests Latest Version PHP 8.3+ License: MIT

Overview

php-youtube-testkit-core lets you test code that uses google/apiclient without hitting real YouTube APIs. Queue fake responses, call Google services as normal, then assert which requests were made.

Supports three YouTube APIs:

  • YouTube Data API — videos, channels, playlists, search, comments
  • YouTube Analytics API — on-demand metrics queries
  • YouTube Reporting API — bulk data exports and scheduled jobs

Framework-agnostic — works with any PHP project and any test runner.

Installation

composer require --dev viewtrender/php-youtube-testkit-core

Requirements

  • PHP 8.3+
  • google/apiclient ^2.15

Quick Start

YouTube Data API

<?php

namespace Tests\Unit;

use PHPUnit\Framework\TestCase;
use Viewtrender\Youtube\YoutubeDataApi;
use Viewtrender\Youtube\Factories\YoutubeVideo;

class VideoServiceTest extends TestCase
{
    protected function tearDown(): void
    {
        YoutubeDataApi::reset();
        parent::tearDown();
    }

    public function test_it_fetches_video_details(): void
    {
        YoutubeDataApi::fake([
            YoutubeVideo::listWithVideos([
                [
                    'id' => 'dQw4w9WgXcQ',
                    'snippet' => [
                        'title' => 'Never Gonna Give You Up',
                        'channelTitle' => 'Rick Astley',
                    ],
                    'statistics' => [
                        'viewCount' => '1500000000',
                        'likeCount' => '15000000',
                    ],
                ],
            ]),
        ]);

        $youtube = YoutubeDataApi::youtube();
        $response = $youtube->videos->listVideos('snippet,statistics', ['id' => 'dQw4w9WgXcQ']);

        $video = $response->getItems()[0];
        $this->assertSame('Never Gonna Give You Up', $video->getSnippet()->getTitle());
        $this->assertSame('1500000000', $video->getStatistics()->getViewCount());

        YoutubeDataApi::assertListedVideos();
        YoutubeDataApi::assertSentCount(1);
    }
}

YouTube Analytics API

<?php

namespace Tests\Unit;

use PHPUnit\Framework\TestCase;
use Viewtrender\Youtube\YoutubeAnalyticsApi;
use Viewtrender\Youtube\Factories\AnalyticsQueryResponse;

class ChannelAnalyticsTest extends TestCase
{
    protected function tearDown(): void
    {
        YoutubeAnalyticsApi::reset();
        parent::tearDown();
    }

    public function test_it_fetches_channel_overview_metrics(): void
    {
        YoutubeAnalyticsApi::fake([
            AnalyticsQueryResponse::channelOverview([
                'views' => 500000,
                'estimatedMinutesWatched' => 1500000,
                'subscribersGained' => 1000,
            ]),
        ]);

        $analytics = YoutubeAnalyticsApi::youtubeAnalytics();
        $response = $analytics->reports->query([
            'ids' => 'channel==MINE',
            'startDate' => '2024-01-01',
            'endDate' => '2024-01-31',
            'metrics' => 'views,estimatedMinutesWatched,subscribersGained',
        ]);

        $row = $response->getRows()[0];
        $this->assertSame(500000, $row[0]);
        $this->assertSame(1500000, $row[1]);
        $this->assertSame(1000, $row[2]);

        YoutubeAnalyticsApi::assertSentCount(1);
    }
}

YouTube Reporting API

<?php

namespace Tests\Unit;

use PHPUnit\Framework\TestCase;
use Viewtrender\Youtube\YoutubeReportingApi;
use Viewtrender\Youtube\Factories\ReportingJob;
use Viewtrender\Youtube\Factories\ReportingReport;
use Viewtrender\Youtube\Factories\ReportingMedia;

class ReportingPipelineTest extends TestCase
{
    protected function tearDown(): void
    {
        YoutubeReportingApi::reset();
        parent::tearDown();
    }

    public function test_it_lists_reporting_jobs(): void
    {
        YoutubeReportingApi::fake([
            ReportingJob::list([
                ['id' => 'job-1', 'reportTypeId' => 'channel_basic_a2', 'name' => 'Daily Stats'],
                ['id' => 'job-2', 'reportTypeId' => 'channel_demographics_a1', 'name' => 'Demographics'],
            ]),
        ]);

        $reporting = YoutubeReportingApi::youtubeReporting();
        $response = $reporting->jobs->listJobs();

        $this->assertCount(2, $response->getJobs());
        $this->assertSame('channel_basic_a2', $response->getJobs()[0]->getReportTypeId());

        YoutubeReportingApi::assertSentCount(1);
    }

    public function test_it_downloads_report_csv(): void
    {
        $csvContent = "date,channel_id,views,watch_time_minutes\n" .
                      "2024-01-01,UC123,1000,5000\n" .
                      "2024-01-02,UC123,1200,6000\n";

        YoutubeReportingApi::fake([
            ReportingMedia::download($csvContent),
        ]);

        $reporting = YoutubeReportingApi::youtubeReporting();
        $response = $reporting->media->download('resource-name');

        $this->assertStringContainsString('views,watch_time_minutes', $response->getBody()->getContents());

        YoutubeReportingApi::assertSentCount(1);
    }
}

YouTube Data API

Setting up fakes

use Viewtrender\Youtube\YoutubeDataApi;
use Viewtrender\Youtube\Factories\YoutubeVideo;
use Viewtrender\Youtube\Factories\YoutubeChannel;

YoutubeDataApi::fake([
    YoutubeVideo::list(),      // first request
    YoutubeChannel::list(),    // second request
]);

Data API Factories

Factory Methods
YoutubeVideo list(), listWithVideos(), video(), empty(), notFound()
YoutubeChannel list(), listWithChannels(), channel(), empty(), notFound()
YoutubePlaylist list(), listWithPlaylists(), playlist(), empty()
YoutubePlaylistItems list(), listWithItems(), empty()
YoutubeSearchResult list(), listWithResults(), searchResult(), empty()
YoutubeCommentThreads list(), listWithThreads(), empty()
YoutubeComments list(), listWithComments(), empty()
YoutubeSubscriptions list(), listWithSubscriptions(), empty()
YoutubeActivities list(), listWithActivities(), empty()
YoutubeCaptions list(), listWithCaptions(), empty()

Custom items

YoutubeVideo::listWithVideos([
    [
        'id' => 'abc123',
        'snippet' => ['title' => 'My Custom Title'],
        'statistics' => ['viewCount' => '999'],
    ],
]);

Data API Assertions

YoutubeDataApi::assertListedVideos();
YoutubeDataApi::assertListedChannels();
YoutubeDataApi::assertListedPlaylists();
YoutubeDataApi::assertSearched();
YoutubeDataApi::assertSentCount(2);
YoutubeDataApi::assertNothingSent();

Pagination

Test code that paginates through multi-page API responses. Pagination is provided by the HasPagination trait on YoutubePlaylistItems and YoutubeActivities — the Data API endpoints that return nextPageToken.

Both methods return array<FakeResponse> — spread them into fake([]):

Method Purpose
paginated(pages, perPage) Auto-generate items with fixture defaults
pages(array) Full control over each page's items

Each factory also provides a named item constructor:

  • YoutubePlaylistItems::playlistItem(array $overrides = [])
  • YoutubeActivities::activity(array $overrides = [])

Auto-Generated Pages

Use paginated() to generate multiple pages of fake items:

use Viewtrender\Youtube\Factories\YoutubePlaylistItems;

// Generate 3 pages with 5 items each
YoutubeDataApi::fake([
    ...YoutubePlaylistItems::paginated(pages: 3, perPage: 5),
]);

// Test pagination logic
$youtube = YoutubeDataApi::youtube();
$pageToken = null;
$allItems = [];

do {
    $response = $youtube->playlistItems->listPlaylistItems(
        'snippet',
        ['playlistId' => 'PLxxx', 'pageToken' => $pageToken]
    );
    $allItems = array_merge($allItems, $response->getItems());
    $pageToken = $response->getNextPageToken();
} while ($pageToken !== null);

$this->assertCount(15, $allItems);

Explicit Page Contents

Use pages() for full control over each page's items. You can pass raw override arrays or use the named constructors:

use Viewtrender\Youtube\Factories\YoutubePlaylistItems;

// Using raw arrays (merged with fixture defaults)
YoutubeDataApi::fake([
    ...YoutubePlaylistItems::pages([
        // Page 1 — includes nextPageToken
        [
            ['snippet' => ['title' => 'First Video', 'resourceId' => ['videoId' => 'vid1']]],
            ['snippet' => ['title' => 'Second Video', 'resourceId' => ['videoId' => 'vid2']]],
        ],
        // Page 2 — last page, no nextPageToken
        [
            ['snippet' => ['title' => 'Third Video', 'resourceId' => ['videoId' => 'vid3']]],
        ],
    ]),
]);

// Using named constructors
YoutubeDataApi::fake([
    ...YoutubeActivities::pages([
        [
            YoutubeActivities::activity([
                'snippet' => ['title' => 'Uploaded: New Video', 'type' => 'upload'],
                'contentDetails' => ['upload' => ['videoId' => 'vid1']],
            ]),
        ],
        [
            YoutubeActivities::activity([
                'snippet' => ['title' => 'Liked: Some Video', 'type' => 'like'],
            ]),
        ],
    ]),
]);

See docs/DATA_API.md for complete reference.

YouTube Analytics API

For on-demand metrics queries — dashboards, real-time stats, custom date ranges.

Setting up fakes

use Viewtrender\Youtube\YoutubeAnalyticsApi;
use Viewtrender\Youtube\Factories\AnalyticsQueryResponse;

YoutubeAnalyticsApi::fake([
    AnalyticsQueryResponse::dailyMetrics([
        ['day' => '2024-01-01', 'views' => 1000],
        ['day' => '2024-01-02', 'views' => 1200],
    ]),
]);

Analytics Factory Methods

Method Description
channelOverview() Channel-level aggregated metrics
dailyMetrics() Day-by-day breakdown
topVideos() Top performing videos
trafficSources() Traffic source breakdown
demographics() Age/gender viewer percentages
geography() Country-level metrics
deviceTypes() Device type breakdown
videoAnalytics() Per-video metrics
videoTypes() Metrics by content type

Channel Overview

AnalyticsQueryResponse::channelOverview([
    'views' => 500000,
    'estimatedMinutesWatched' => 1500000,
    'averageViewDuration' => 180,
    'subscribersGained' => 1000,
    'subscribersLost' => 50,
]);

Traffic Sources

AnalyticsQueryResponse::trafficSources([
    ['source' => 'RELATED_VIDEO', 'views' => 500000],
    ['source' => 'YT_SEARCH', 'views' => 300000],
    ['source' => 'EXT_URL', 'views' => 100000],
]);

Demographics

AnalyticsQueryResponse::demographics([
    ['ageGroup' => 'age18-24', 'gender' => 'male', 'viewerPercentage' => 25.5],
    ['ageGroup' => 'age25-34', 'gender' => 'female', 'viewerPercentage' => 18.2],
]);

Content Types

AnalyticsQueryResponse::videoTypes([
    ['video' => 'abc123', 'creatorContentType' => 'VIDEO_ON_DEMAND', 'views' => 180000],
    ['video' => 'def456', 'creatorContentType' => 'SHORTS', 'views' => 120000],
    ['video' => 'ghi789', 'creatorContentType' => 'LIVE_STREAM', 'views' => 50000],
]);

See docs/ANALYTICS_API.md for complete metrics and dimensions reference.

YouTube Reporting API

For bulk data exports — background jobs, historical data pipelines, scheduled reports.

Workflow: Create job → Poll for reports → Download CSV → Parse & upsert

Setting up fakes

use Viewtrender\Youtube\YoutubeReportingApi;
use Viewtrender\Youtube\Factories\ReportingJob;
use Viewtrender\Youtube\Factories\ReportingReport;
use Viewtrender\Youtube\Factories\ReportingReportType;
use Viewtrender\Youtube\Factories\ReportingMedia;

YoutubeReportingApi::fake([
    ReportingJob::create(['id' => 'job-123', 'reportTypeId' => 'channel_basic_a2']),
]);

Reporting Factories

Factory Methods
ReportingJob create(), list(), delete()
ReportingReport list(), get()
ReportingReportType list()
ReportingMedia download()

Creating a Job

ReportingJob::create([
    'id' => 'job-123',
    'reportTypeId' => 'channel_basic_a2',
    'name' => 'My Channel Report',
]);

Listing Jobs

ReportingJob::list([
    ['id' => 'job-1', 'reportTypeId' => 'channel_basic_a2', 'name' => 'Job 1'],
    ['id' => 'job-2', 'reportTypeId' => 'channel_demographics_a1', 'name' => 'Job 2'],
]);

Listing Reports

ReportingReport::list([
    [
        'id' => 'report-1',
        'jobId' => 'job-123',
        'startTime' => '2024-01-01T00:00:00Z',
        'endTime' => '2024-01-02T00:00:00Z',
        'downloadUrl' => 'https://youtube.com/reporting/v1/media/report-1',
    ],
]);

Downloading CSV Data

$csv = "date,channel_id,views,watch_time_minutes\n" .
       "2024-01-01,UC123,1000,5000\n";

ReportingMedia::download($csv);

Common Report Types

Report Type ID Description
channel_basic_a2 Core channel metrics
channel_demographics_a1 Viewer age/gender
channel_device_os_a2 Device and OS distribution
channel_traffic_source_a2 Traffic source breakdown

See docs/REPORTING_API.md for complete reference.

Error Responses

Simulate API errors for any service:

use Viewtrender\Youtube\Responses\ErrorResponse;

YoutubeDataApi::fake([
    ErrorResponse::notFound('Video not found.'),
    ErrorResponse::quotaExceeded('Daily quota exhausted.'),
    ErrorResponse::forbidden(),
    ErrorResponse::unauthorized(),
    ErrorResponse::badRequest(),
]);

Custom Responses

Build arbitrary responses with FakeResponse:

use Viewtrender\Youtube\Responses\FakeResponse;

FakeResponse::make(['kind' => 'youtube#videoListResponse', 'items' => []]);
FakeResponse::fromFixture('youtube/videos-list.json');
FakeResponse::make(['error' => 'bad'])->status(400);

Preventing Stray Requests

Throw an exception when no fake response is queued:

$fake = YoutubeDataApi::fake([YoutubeVideo::list()]);
$fake->preventStrayRequests();

Framework Integration

Register a callback that runs whenever fake() is called:

YoutubeDataApi::registerContainerSwap(function () {
    $container->set(YouTube::class, new YouTube(YoutubeDataApi::client()));
});

License

MIT

viewtrender/php-youtube-testkit-core 适用场景与选型建议

viewtrender/php-youtube-testkit-core 是一款 基于 PHP 开发的 Composer 扩展包,目前已累计 55 次下载、GitHub Stars 达 1, 最近一次更新时间为 2026 年 02 月 19 日, 在 PHP 生态内属于活跃度较高的组件。

我们在过去多个企业项目中使用过 viewtrender/php-youtube-testkit-core 或与其功能相近的方案,如果你在选型或落地过程中遇到问题,例如 版本兼容、二次改造、私有化封装、与内部系统对接、生产 BUG 排查,欢迎联系我们协助评估。

围绕 viewtrender/php-youtube-testkit-core 我们能提供哪些服务?
定制开发 / 二次开发

基于 viewtrender/php-youtube-testkit-core 在你已有业务上做功能扩展、字段裁剪、UI 适配、与内部账号 / 权限 / 日志系统的深度对接。

BUG 修复 & 性能优化

线上偶发问题、内存泄漏、慢查询、并发异常等排查修复;针对高流量场景做缓存、队列、索引层面的调优。

项目外包 & 长期维护

承接完整的项目从需求 → 设计 → 开发 → 上线 → 长期运维;也可按月提供技术保姆服务。

yvsm@zunyunkeji.com QQ:316430983 微信:yvsm316 西安尊云信息科技 · 专注 PHP / Go / 分布式系统研发

统计信息

  • 总下载量: 55
  • 月度下载量: 0
  • 日度下载量: 0
  • 收藏数: 1
  • 点击次数: 22
  • 依赖项目数: 1
  • 推荐数: 0

GitHub 信息

  • Stars: 1
  • Watchers: 0
  • Forks: 0
  • 开发语言: PHP

其他信息

  • 授权协议: MIT
  • 更新时间: 2026-02-19