laravel-bluesky 的主要功能都是通过 Bluesky Facade 提供的,因此可以使用标准的 Laravel mock 进行测试。关于扩展包开发的整体测试思路,请参考 package-testing。
Facade mock
使用 Bluesky::expects() 可以对整条方法链进行 mock。
use Revolution\Bluesky\Facades\Bluesky;
use Illuminate\Support\Facades\Http;
use Illuminate\Http\Client\Response;
Bluesky::expects('login->getProfile->json')->once()->andReturn([]);
Bluesky::expects('login->getProfile')->once()->andReturn(new Response(Http::response([])->wait()));
HTTP fake
laravel-bluesky 内部使用 Laravel 的 HTTP 客户端。将 Http::preventStrayRequests() 写入 setUp(),就能立刻发现意外的外部请求。
use Revolution\Bluesky\Facades\Bluesky;
use Illuminate\Support\Facades\Http;
protected function setUp(): void
{
parent::setUp();
Http::preventStrayRequests();
}
public function test_post(): void
{
Http::fake();
Http::fakeSequence()
->push();
Bluesky::expects('resolveHandle->json')->once()->andReturn('did');
}
Http::preventStrayRequests() 会在测试执行中发生真实外部请求时抛出异常。这样能第一时间发现非预期的外部通信,提高测试的可靠性。
无法 mock 的功能
FeedGenerator
FeedGenerator 是由 Bluesky 服务端发起调用的,因此没有端到端的 mock 方式。不过,FeedGenerator 的算法部分是可以 mock 的。
use Revolution\Bluesky\Facades\Bluesky;
use Revolution\Bluesky\FeedGenerator\FeedGenerator;
public function test_feed_generator(): void
{
FeedGenerator::register(name: 'test', algo: function (?int $limit, ?string $cursor) {
// 由于 API 限制,这里需要认证
$posts = Bluesky::login(identifier: config('bluesky.identifier'), password: config('bluesky.password'))
->searchPosts(q: '#bluesky')->collect('posts');
$feed = $posts->map(function (array $post) {
return ['post' => data_get($post, 'uri')];
})->toArray();
return ['feed' => $feed];
});
Bluesky::expects('login->searchPosts->collect')->once()->andReturn(collect([['uri' => 'at://']]));
$response = $this->get(route('bluesky.feed.skeleton', ['feed' => 'at://did:/app.bsky.feed.generator/test']));
$response->assertSuccessful();
$response->assertJson(['feed' => [['post' => 'at://']]]);
}
Core
Bluesky/AtProtocol 的核心功能不涉及外部访问,因此不需要 mock。