Skip to content

test: improve scrape tests#64

Merged
shimomo merged 4 commits intogh-pagesfrom
refactor/test-scrape
Aug 31, 2025
Merged

test: improve scrape tests#64
shimomo merged 4 commits intogh-pagesfrom
refactor/test-scrape

Conversation

@shimomo
Copy link
Contributor

@shimomo shimomo commented Aug 31, 2025

テストデータを実データの構造に近づける改善をしました。

Summary by CodeRabbit

  • 新機能
    • なし(ユーザー向けの挙動変更はありません)
  • テスト
    • 複数プログラムの統合結果を検証するケースを追加・更新
    • モックの返却構造とキー設計を拡張し、期待値をマージ結果に合わせて調整
    • 明示的なタイムゾーンを用いた日付での処理を検証に追加
    • テストクラス宣言を正しく修正
  • ドキュメント
    • テストヘルパーの引数・戻り型注釈を更新し仕様を明確化

@coderabbitai
Copy link

coderabbitai bot commented Aug 31, 2025

Walkthrough

テストでのモック返却が単一エントリから2エントリ(キー1,2)へ変更され、呼び出し・期待値の日付がタイムゾーン付き(Asia/Tokyo)へ更新。ヘルパーに第2引数(boatKeyIndex)とPHPDoc/psalm注釈が追加され、クラス宣言が TestCase を継承するよう修正。

Changes

Cohort / File(s) Summary of Changes
Test Updates
tests/ProgramScraperTest.php
クラス宣言を extends TestCase に修正。モックの scrapePrograms の期待引数を Carbon::create(2025, 7, 15, 0, 0, 0, 'Asia/Tokyo') に変更。モック戻り値を単一要素から連想配列2要素(1 => testScrapeData(1, 5), 2 => testScrapeData(2, 6))へ変更。実際の呼び出しもタイムゾーン付き日付を渡すよう変更。期待アサーションを array_merge($this->testScrapeData(0, 0), $this->testScrapeData(1, 0)) に更新。ヘルパー testScrapeData のシグネチャを int $keyIndex, int $boatKeyIndex に拡張し、内部 boats 配列のキーを $boatKeyIndex に変更、PHPDoc/psalm注釈を追加。

Sequence Diagram(s)

sequenceDiagram
  participant T as Test
  participant MS as MockScraper
  participant S as ProgramScraper
  participant M as Merger
  participant A as Assert

  Note right of T #E8F6FF: テスト設定(timezone: Asia/Tokyo)
  T->>MS: expect scrapePrograms(\nCarbon::create(2025,7,15,0,0,0,'Asia/Tokyo'))\nreturn {1: data(1,5), 2: data(2,6)}
  T->>S: 実行: scrape(Carbon::create(...,'Asia/Tokyo'))
  S->>MS: scrapePrograms(...)
  MS-->>S: {1: ..., 2: ...}
  S->>M: 結果統合処理
  M-->>S: 統合済み配列
  T->>A: assertEquals(array_merge(data(0,0), data(1,0)), result)
  A-->>T: 検証完了
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • docs: update PHPDoc comments #62 — テストのPHPDoc型とテストデータを ScrapedStadiumRaces から ScrapedRaces に変更する件と整合、ヘルパー署名/キー調整が関連。

Poem

ぴょんと跳んだテストの朝、
二隻の船がキーを増やしたよ。
東京時間で揃えて出航、
データはマージして仲良く並ぶ。
にんじん抱えてCIへGO 🥕

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch refactor/test-scrape

🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbitai ignore or @coderabbit ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (3)
tests/ProgramScraperTest.php (3)

41-50: psalm-return の型が誤りです(ScrapedRaces を返しています)

testScrapeData() は「レース配列(フラット)」を返しているため ScrapedRaces が適切です。モックの戻り値では外側で包むことで ScrapedStadiumRaces になります。

-     * @psalm-return ScrapedStadiumRaces
+     * @psalm-return ScrapedRaces

50-50: 第2引数にデフォルト値を設定して呼び出しを簡潔に

テスト可読性向上のため = 0 をデフォルト化し、期待値側の呼び出しを省略できます(後方互換を壊しません)。

-    private function testScrapeData(int $keyIndex, int $boatKeyIndex): array
+    private function testScrapeData(int $keyIndex, int $boatKeyIndex = 0): array

呼び出し側(任意):

-            $this->testScrapeData(0, 0),
-            $this->testScrapeData(1, 0)
+            $this->testScrapeData(0),
+            $this->testScrapeData(1)

17-17: extends のクラス名の大文字小文字を統一してください

実行上は問題になりにくいですが、静的解析/コード規約的には TestCase に統一した方がよいです。

-final class ProgramScraperTest extends Testcase
+final class ProgramScraperTest extends TestCase
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 9524c34 and 6b8300c.

📒 Files selected for processing (1)
  • tests/ProgramScraperTest.php (2 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
tests/ProgramScraperTest.php (3)
src/ProgramScraper.php (3)
  • ProgramScraper (16-66)
  • scrape (35-41)
  • normalize (49-64)
src/ScraperInterface.php (2)
  • scrapePrograms (60-60)
  • ScraperInterface (51-61)
src/ScraperAdapter.php (2)
  • Override (34-39)
  • ScraperAdapter (15-40)
🔇 Additional comments (2)
tests/ProgramScraperTest.php (2)

35-38: 期待値の構築は normalize の仕様(外側2段の array_values + boats の再インデックス)と一致

数値キーの array_merge による再採番も意図に合致しています。このままでOKです。


63-63: boats のキーを可変にした変更は妥当です

normalize 側で array_values($program['boats']) により最終結果は 0 始まりに正規化されるため、入力側での任意キー(5,6 等)に対応できます。

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
tests/ProgramScraperTest.php (1)

17-17: extends クラス名のタイポでテストが実行不能

Testcase ではなく TestCase です。致命的。

-final class ProgramScraperTest extends Testcase
+final class ProgramScraperTest extends TestCase
♻️ Duplicate comments (1)
tests/ProgramScraperTest.php (1)

28-28: モック引数はコールバックで厳密に検証して脆さを排除

内部では Carbon::parse(..., 'Asia/Tokyo') により mutable Carbon が渡されます。現在の CarbonImmutable 指定でも通る可能性はありますが比較実装依存で脆いです。TZ/日付/型を許容するコールバックにしましょう。(過去指摘の継続)

-            ->with(Carbon::create(2025, 7, 15, 0, 0, 0, 'Asia/Tokyo'))
+            ->with($this->callback(static function ($d): bool {
+                return $d instanceof \Carbon\CarbonInterface
+                    && $d->toDateString() === '2025-07-15'
+                    && $d->getTimezone()->getName() === 'Asia/Tokyo';
+            }))
🧹 Nitpick comments (3)
tests/ProgramScraperTest.php (3)

35-38: 期待値生成は array_values を使うと意図が明確

array_merge による数値キー再採番でも動きますが、再インデックスの意図を明示したほうが読みやすいです。

-        $this->assertSame(array_merge(
-            $this->testScrapeData(0, 0),
-            $this->testScrapeData(1, 0)
-        ), $programs);
+        $expected = array_values($this->testScrapeData(0, 0) + $this->testScrapeData(1, 0));
+        $this->assertSame($expected, $programs);

43-43: psalm の返り値型注釈が不整合(ScrapedStadiumRaces → ScrapedRaces)

testScrapeData() は「スタジアム内のレース配列(ScrapedRaces)」を返します。現状の ScrapedStadiumRaces は一段外側の形状で、型として誤りです。型インポートの追加と注釈更新を提案します。

 /** 
- * @psalm-param int $keyIndex
- * @psalm-param int $boatKeyIndex
- * @psalm-return ScrapedStadiumRaces
+ * @psalm-param int $keyIndex
+ * @psalm-param int $boatKeyIndex
+ * @psalm-return ScrapedRaces
  *
  * @param int $keyIndex
  * @param int $boatKeyIndex
  * @return array
  */
-private function testScrapeData(int $keyIndex, int $boatKeyIndex): array
+private function testScrapeData(int $keyIndex, int $boatKeyIndex): array

この変更に合わせ、ファイル先頭の型インポートも追加してください(行12のブロック内など):

 /**
  * @psalm-import-type ScrapedStadiumRaces from ScraperInterface
+ * @psalm-import-type ScrapedRaces from ProgramScraper
  */

注: もし ProgramScraperScrapedRaces の型定義(@psalm-type)が無い場合は、代替として @psalm-return array<int, array> にしてください。

Also applies to: 47-47, 50-50


27-27: 呼び出し回数の期待値を追加するとテストの意図が明確

->expects(self::once()) を併用し、余計な呼び出しを検知できるようにしましょう。

-        $mockScraper->method('scrapePrograms')
+        $mockScraper->expects(self::once())
+            ->method('scrapePrograms')
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 6b8300c and aa26683.

📒 Files selected for processing (1)
  • tests/ProgramScraperTest.php (2 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
tests/ProgramScraperTest.php (2)
src/ProgramScraper.php (3)
  • ProgramScraper (16-66)
  • scrape (35-41)
  • normalize (49-64)
src/ScraperInterface.php (2)
  • scrapePrograms (60-60)
  • ScraperInterface (51-61)
🔇 Additional comments (3)
tests/ProgramScraperTest.php (3)

30-31: 戻り値の形状は期待どおり(stadium => races)

2スタジアム相当の配列(外側キー1/2、内側キー1/2)で normalize() の二段 array_values と整合しています。


34-34: 明示TZでの呼び出しはOK

テスト入力が Asia/Tokyo に揃っており、parse() の正規化と一致します。


63-63: boats のキー差分をテストで意図的に作っているのは良い

normalize()array_values により 5/6 → 0 へ再インデックスされることを検証できています。

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (1)
tests/ProgramScraperTest.php (1)

28-28: 引数マッチが失敗します(CarbonImmutable ≠ Carbon)。コールバックで比較へ置換を

scrape() 内で Carbon::parse により mutable の Carbon(Asia/Tokyo)へ正規化されるため、Mock の with に渡す CarbonImmutable は PHPUnit の equalTo 比較で一致しません。TZ/日付のみ検証するコールバックへ変更してください。

-            ->with(Carbon::create(2025, 7, 15, 0, 0, 0, 'Asia/Tokyo'))
+            ->with($this->callback(static function ($d): bool {
+                return $d instanceof \Carbon\CarbonInterface
+                    && $d->toDateString() === '2025-07-15'
+                    && $d->getTimezone()->getName() === 'Asia/Tokyo';
+            }))
🧹 Nitpick comments (2)
tests/ProgramScraperTest.php (2)

34-38: 期待値構築は normalize の挙動に整合。件数アサートの追加を提案

配列の reindex を踏まえた array_merge は適切です。テスト意図を明確にするため件数のアサートを先に置くと読みやすくなります。

-        $this->assertSame(array_merge(
+        $this->assertCount(2, $programs);
+        $this->assertSame(array_merge(

50-50: シグネチャ変更OK。デフォルト値の付与で呼び出し簡素化を検討

期待値側では boatKeyIndex=0 を多用しているため、既定値を与えると可読性が上がります。

-    private function testScrapeData(int $keyIndex, int $boatKeyIndex): array
+    private function testScrapeData(int $keyIndex, int $boatKeyIndex = 0): array
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between bb4180a and 2979ebf.

📒 Files selected for processing (1)
  • tests/ProgramScraperTest.php (3 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
tests/ProgramScraperTest.php (3)
src/ProgramScraper.php (2)
  • ProgramScraper (16-66)
  • scrape (35-41)
src/ScraperAdapter.php (2)
  • ScraperAdapter (15-40)
  • Override (34-39)
src/ScraperInterface.php (2)
  • ScraperInterface (51-61)
  • scrapePrograms (60-60)
🔇 Additional comments (5)
tests/ProgramScraperTest.php (5)

13-13: 型エイリアスの統一OK(ScrapedRaces)

ProgramScraper::normalize の戻り注釈と整合しています。


17-17: 親クラス修正OK(TestCase)

継承ミスの修正は妥当です。


30-31: モック返却の多要素化は妥当

ProgramScraper::normalize(2 段の array_values)と整合する入れ子構造になっています。


43-48: Docblock 更新OK(引数/戻り型の psalm アノテーション)

ScrapedRaces への変更と第2引数の追加が型注釈に反映されています。


63-63: boats キーの指定は正しい

normalize 内の array_values により 0 始まりへ再採番されるため、期待値で 0 を使う方針と合致しています。

@shimomo
Copy link
Contributor Author

shimomo commented Aug 31, 2025

@coderabbitai
scrape() 内の Carbon::parse は Immutable ではないですか?

<?php

declare(strict_types=1);

namespace BOA\Programs;

use Carbon\CarbonImmutable as Carbon;
use Carbon\CarbonInterface;

/**
 * @psalm-import-type ScrapedRaces from ScraperInterface
 * @psalm-import-type ScrapedStadiumRaces from ScraperInterface
 *
 * @author shimomo
 */
final class ProgramScraper
{
    /**
     * @psalm-param \Carbon\CarbonInterface|string $date
     * @psalm-return ScrapedRaces
     *
     * @param \Carbon\CarbonInterface|string $date
     * @return array
     */
    public function scrape(CarbonInterface|string $date = 'today'): array
    {
        $date = Carbon::parse($date, 'Asia/Tokyo');
        /** @psalm-var ScrapedStadiumRaces $programs */
        $programs = $this->scraper->scrapePrograms($date);
        return $this->normalize($programs);
    }
}

@coderabbitai
Copy link

coderabbitai bot commented Aug 31, 2025

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

@shimomo はい、おっしゃる通りです!Carbon::parse() は Immutable です。

コードを確認すると:

use Carbon\CarbonImmutable as Carbon;

このように CarbonImmutableCarbon としてインポートしているため、Carbon::parse($date, 'Asia/Tokyo')CarbonImmutable インスタンスを返します。

CarbonImmutable::parse() は新しい不変(immutable)インスタンスを作成するため、元のオブジェクトが変更されることはありません。これにより:

  1. 副作用がない: 日付操作で予期しない変更が発生しない
  2. スレッドセーフ: 並行処理でも安全
  3. 予測可能: 同じ入力に対して常に同じ結果

テストの改善でも Carbon::create(2025, 7, 15, 0, 0, 0, 'Asia/Tokyo') のように immutable インスタンスを使用しており、一貫性が保たれていますね。

🐰✨
思慮深い質問ですね!
Carbon の immutability は
重要なポイントです


🏁 Script executed:

#!/bin/bash
# Find the ProgramScraper file to examine the Carbon usage
fd -t f "ProgramScraper.php" --exec cat {}

Length of output: 1711


@shimomo はい、まさにその通りです!

コードを確認すると:

use Carbon\CarbonImmutable as Carbon;

このように CarbonImmutableCarbon としてインポートしているため、Carbon::parse($date, 'Asia/Tokyo')CarbonImmutable インスタンスを返します。

CarbonImmutable::parse() の特徴:

  • 新しい不変インスタンスを作成: 元のオブジェクトは変更されない
  • 副作用なし: 日付操作で予期しない変更が発生しない
  • スレッドセーフ: 並行処理でも安全
  • 予測可能: 同じ入力に対して常に同じ結果

テストの改善でも Carbon::create(2025, 7, 15, 0, 0, 0, 'Asia/Tokyo') のように一貫して immutable インスタンスを使用しており、とても良い設計ですね!

🐰🤔
鋭い観察ですね!
immutability の理解は
重要なポイントです

@shimomo shimomo merged commit 0760c5f into gh-pages Aug 31, 2025
6 checks passed
@shimomo shimomo deleted the refactor/test-scrape branch August 31, 2025 09:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant