feat: Add Excel export functionality and unit tests

Features:
- Excel export with formatted multi-sheet workbooks (Contents, Comments, Creators)
- Professional styling: blue headers, auto-width columns, borders, text wrapping
- Smart export: empty sheets automatically removed
- Support for all platforms (xhs, dy, ks, bili, wb, tieba, zhihu)

Testing:
- Added pytest framework with asyncio support
- Unit tests for Excel store functionality
- Unit tests for store factory pattern
- Shared fixtures for test data
- Test coverage for edge cases

Documentation:
- Comprehensive Excel export guide (docs/excel_export_guide.md)
- Updated README.md and README_en.md with Excel examples
- Updated config comments to include excel option

Dependencies:
- Added openpyxl>=3.1.2 for Excel support
- Added pytest>=7.4.0 and pytest-asyncio>=0.21.0 for testing

This contribution adds immediate value for users who need data analysis
capabilities and establishes a testing foundation for future development.
This commit is contained in:
hsparks.codes
2025-11-28 04:44:12 +01:00
parent 31a092c653
commit 46ef86ddef
14 changed files with 881 additions and 4 deletions

View File

@@ -0,0 +1,75 @@
# -*- coding: utf-8 -*-
"""
Unit tests for Store Factory functionality
"""
import pytest
from unittest.mock import patch, MagicMock
from store.xhs import XhsStoreFactory
from store.xhs._store_impl import (
XhsCsvStoreImplement,
XhsJsonStoreImplement,
XhsDbStoreImplement,
XhsSqliteStoreImplement,
XhsMongoStoreImplement,
XhsExcelStoreImplement
)
class TestXhsStoreFactory:
"""Test cases for XhsStoreFactory"""
@patch('config.SAVE_DATA_OPTION', 'csv')
def test_create_csv_store(self):
"""Test creating CSV store"""
store = XhsStoreFactory.create_store()
assert isinstance(store, XhsCsvStoreImplement)
@patch('config.SAVE_DATA_OPTION', 'json')
def test_create_json_store(self):
"""Test creating JSON store"""
store = XhsStoreFactory.create_store()
assert isinstance(store, XhsJsonStoreImplement)
@patch('config.SAVE_DATA_OPTION', 'db')
def test_create_db_store(self):
"""Test creating database store"""
store = XhsStoreFactory.create_store()
assert isinstance(store, XhsDbStoreImplement)
@patch('config.SAVE_DATA_OPTION', 'sqlite')
def test_create_sqlite_store(self):
"""Test creating SQLite store"""
store = XhsStoreFactory.create_store()
assert isinstance(store, XhsSqliteStoreImplement)
@patch('config.SAVE_DATA_OPTION', 'mongodb')
def test_create_mongodb_store(self):
"""Test creating MongoDB store"""
store = XhsStoreFactory.create_store()
assert isinstance(store, XhsMongoStoreImplement)
@patch('config.SAVE_DATA_OPTION', 'excel')
@patch('var.crawler_type_var.get', return_value='search')
def test_create_excel_store(self, mock_crawler_type):
"""Test creating Excel store"""
store = XhsStoreFactory.create_store()
assert isinstance(store, XhsExcelStoreImplement)
@patch('config.SAVE_DATA_OPTION', 'invalid')
def test_invalid_store_option(self):
"""Test that invalid store option raises ValueError"""
with pytest.raises(ValueError) as exc_info:
XhsStoreFactory.create_store()
assert "Invalid save option" in str(exc_info.value)
def test_all_stores_registered(self):
"""Test that all store types are registered"""
expected_stores = ['csv', 'json', 'db', 'sqlite', 'mongodb', 'excel']
for store_type in expected_stores:
assert store_type in XhsStoreFactory.STORES
assert len(XhsStoreFactory.STORES) == len(expected_stores)