test(09-00): add Wave 0 test scaffolding for Pipeline integration

- Add mock fixtures for ZhihuCrawler CrawlResult models:
  - mock_crawl_answer_result: simulates answer crawl with comments
  - mock_crawl_article_result: simulates zhuanlan article crawl
  - mock_comments_list: test data for comment formatting
  - mock_zhihu_login_result: simulates QR code login success
  - mock_crawl_failed_result: for error handling tests

- Add test skeletons (marked skip) for Wave 1 implementation:
  - test_fetch_metadata_answer
  - test_fetch_metadata_article
  - test_fetch_content_with_comments
  - test_cookie_expired_triggers_login
  - test_idempotent_execution
  - test_comment_formatting

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-17 22:59:07 +08:00
parent bee696b96d
commit 95218c18cd
+272
View File
@@ -6,15 +6,197 @@ Tests cover:
- Cookie-based authentication
- Login page detection
- AuthError handling
Wave 0 Test Scaffolding (Phase 09 - Pipeline Integration):
- Mock fixtures for ZhihuCrawler CrawlResult
- Test skeletons for integration with new crawler
"""
import pytest
from unittest.mock import MagicMock, patch, PropertyMock
import asyncio
from pathlib import Path
from kb_workflow.pipeline.platforms.zhihu import ZhihuAdapter
from kb_workflow.pipeline.errors import AuthError
# =============================================================================
# Wave 0 Mock Fixtures for ZhihuCrawler Integration (Phase 09)
# =============================================================================
@pytest.fixture
def mock_crawl_answer_result():
"""Mock CrawlResult from ZhihuCrawler.crawl_answer().
Simulates successful answer crawl with metadata and content.
Used for testing ZhihuAdapter integration with new crawler.
"""
from kb_workflow.crawler.models import (
CrawlResult, AnswerData, AuthorInfo, ContentMetadata, CommentData, CommentAuthor
)
return CrawlResult(
success=True,
content_type="answer",
data=AnswerData(
id=789012,
question_id=123456,
question_title="Test Question Title for Pipeline Integration",
content="<p>This is the <strong>answer</strong> content from ZhihuCrawler.</p>",
excerpt="This is the answer content from ZhihuCrawler.",
metadata=ContentMetadata(
author=AuthorInfo(
name="Test Author",
url_token="test-author-123",
headline="Test Author Headline"
),
voteup_count=1234,
comment_count=56,
created_time=1705312800, # 2024-01-15 10:00:00 UTC
updated_time=1705399200 # 2024-01-16 10:00:00 UTC
)
),
comments=[
CommentData(
id=111,
content="Great answer! Very helpful.",
author=CommentAuthor(name="Commenter1", url_token="commenter-1"),
created_time=1705316400,
like_count=42,
child_count=3,
is_author=False
),
CommentData(
id=222,
content="Thanks for sharing!",
author=CommentAuthor(name="Commenter2", url_token="commenter-2"),
created_time=1705320000,
like_count=15,
child_count=0,
is_author=False
)
],
error=None
)
@pytest.fixture
def mock_crawl_article_result():
"""Mock CrawlResult from ZhihuCrawler.crawl_article().
Simulates successful zhuanlan article crawl.
Used for testing ZhihuAdapter integration with new crawler.
"""
from kb_workflow.crawler.models import (
CrawlResult, ArticleData, AuthorInfo, ContentMetadata, CommentData, CommentAuthor
)
return CrawlResult(
success=True,
content_type="article",
data=ArticleData(
id=123456,
title="Test Article Title for Pipeline Integration",
content="<h1>Article Content</h1><p>This is the <em>article</em> content.</p>",
excerpt="Article Content This is the article content.",
metadata=ContentMetadata(
author=AuthorInfo(
name="Test Article Author",
url_token="test-article-author",
headline="Writer and Developer"
),
voteup_count=5678,
comment_count=89,
created_time=1705226400, # 2024-01-14 10:00:00 UTC
updated_time=None
)
),
comments=[
CommentData(
id=333,
content="Excellent article!",
author=CommentAuthor(name="Reader1", url_token="reader-1"),
created_time=1705230000,
like_count=28,
child_count=1,
is_author=False
)
],
error=None
)
@pytest.fixture
def mock_comments_list():
"""Mock list of CommentData for testing comment formatting.
Provides a realistic set of comments with various attributes.
"""
from kb_workflow.crawler.models import CommentData, CommentAuthor
return [
CommentData(
id=1001,
content="This is the first comment with some content.",
author=CommentAuthor(name="User1", url_token="user-1"),
created_time=1705316400,
like_count=100,
child_count=5,
is_author=False
),
CommentData(
id=1002,
content="This is the second comment, from the author.",
author=CommentAuthor(name="AuthorName", url_token="author-token"),
created_time=1705320000,
like_count=50,
child_count=2,
is_author=True
),
CommentData(
id=1003,
content="Third comment here.",
author=CommentAuthor(name="User3", url_token="user-3"),
created_time=1705323600,
like_count=25,
child_count=0,
is_author=False
)
]
@pytest.fixture
def mock_zhihu_login_result():
"""Mock ZhihuLoginResult from ZhihuLogin.login_by_qrcode().
Simulates successful QR code login result.
Used for testing cookie refresh flow.
"""
from kb_workflow.auth.zhihu_login import ZhihuLoginResult
from pathlib import Path
return ZhihuLoginResult(
success=True,
cookie_str="z_c0=test_cookie_value; _xsrf=test_xsrf; d_c0=test_d_c0",
qrcode_path=Path("/tmp/test_qrcode.png"),
error_message=None
)
@pytest.fixture
def mock_crawl_failed_result():
"""Mock failed CrawlResult for error handling tests."""
from kb_workflow.crawler.models import CrawlResult
return CrawlResult(
success=False,
content_type="answer",
data=None,
comments=None,
error="Cookie expired or invalid"
)
class TestZhihuAdapterAnswerContent:
"""Tests for ZhihuAdapter answer extraction"""
@@ -181,3 +363,93 @@ class TestZhihuAdapterCookieHandling:
adapter = ZhihuAdapter()
adapter._cookie = "test" # Avoid config loading
assert adapter.PLATFORM == "zhihu"
# =============================================================================
# Wave 0 Test Skeletons for Pipeline Integration (Phase 09)
# These tests are marked skip until ZhihuAdapter is updated to use ZhihuCrawler
# =============================================================================
@pytest.mark.skip(reason="Wave 0 skeleton - awaiting ZhihuCrawler integration")
class TestZhihuAdapterCrawlerIntegration:
"""Test skeletons for ZhihuAdapter integration with ZhihuCrawler.
These tests will verify the adapter correctly uses the new ZhihuCrawler
instead of ZhihuPlaywrightExtractor.
"""
@pytest.mark.asyncio
async def test_fetch_metadata_answer(self, mock_crawl_answer_result):
"""Test fetching answer metadata via ZhihuCrawler.
Verifies:
- ZhihuCrawler.crawl_answer() is called with correct ID
- Metadata is correctly extracted from CrawlResult
- Output format matches expected adapter response
"""
pass
@pytest.mark.asyncio
async def test_fetch_metadata_article(self, mock_crawl_article_result):
"""Test fetching zhuanlan article metadata via ZhihuCrawler.
Verifies:
- ZhihuCrawler.crawl_article() is called with correct ID
- Metadata is correctly extracted from CrawlResult
- Output format matches expected adapter response
"""
pass
@pytest.mark.asyncio
async def test_fetch_content_with_comments(
self, mock_crawl_answer_result, mock_comments_list
):
"""Test fetching content with comments appended.
Verifies:
- Content is fetched with include_comments=True
- Comments are appended to content in correct Markdown format
- Comment format: numbered list with author mention
"""
pass
@pytest.mark.asyncio
async def test_cookie_expired_triggers_login(
self, mock_crawl_failed_result, mock_zhihu_login_result
):
"""Test that expired cookie triggers QR code login flow.
Verifies:
- CrawlResult with success=False triggers login
- ZhihuLogin.login_by_qrcode() is called
- New cookie is used to retry the fetch
- User sees QR code prompt
"""
pass
@pytest.mark.asyncio
async def test_idempotent_execution(self, mock_crawl_answer_result):
"""Test that repeated calls with same content_id are idempotent.
Verifies:
- Multiple calls with same ID produce same result
- No duplicate fetches are made
- State is correctly managed
"""
pass
def test_comment_formatting(self, mock_comments_list):
"""Test comment formatting to Markdown.
Verifies:
- Comments are formatted as numbered list
- Author name is bold/mentioned
- Like count is included
- Format matches expected style:
1. **@AuthorName** (100 likes): Comment content...
"""
pass
# WAVE_0_COMPLETE: Test scaffolding ready for implementation