Initial commit: Market Trends Scraper
This commit is contained in:
165
tests/test_config_manager.py
Normal file
165
tests/test_config_manager.py
Normal file
@@ -0,0 +1,165 @@
|
||||
"""
|
||||
Unit tests for the ConfigManager module.
|
||||
"""
|
||||
|
||||
import pytest
|
||||
import tempfile
|
||||
import os
|
||||
import yaml
|
||||
from pathlib import Path
|
||||
from unittest.mock import patch, mock_open
|
||||
|
||||
from src.config_manager import ConfigManager
|
||||
|
||||
|
||||
class TestConfigManager:
|
||||
"""Test cases for ConfigManager class."""
|
||||
|
||||
def test_init_with_default_path(self):
|
||||
"""Test ConfigManager initialization with default path."""
|
||||
config_manager = ConfigManager()
|
||||
assert config_manager.config_path == Path("config/config.yaml")
|
||||
assert isinstance(config_manager.config, dict)
|
||||
assert isinstance(config_manager.default_config, dict)
|
||||
|
||||
def test_init_with_custom_path(self):
|
||||
"""Test ConfigManager initialization with custom path."""
|
||||
custom_path = "custom/config.yaml"
|
||||
config_manager = ConfigManager(custom_path)
|
||||
assert config_manager.config_path == Path(custom_path)
|
||||
|
||||
def test_get_default_config(self):
|
||||
"""Test default configuration structure."""
|
||||
config_manager = ConfigManager()
|
||||
default_config = config_manager._get_default_config()
|
||||
|
||||
# Check required sections
|
||||
assert "scraper" in default_config
|
||||
assert "sources" in default_config
|
||||
assert "output" in default_config
|
||||
assert "database" in default_config
|
||||
assert "analysis" in default_config
|
||||
|
||||
# Check some default values
|
||||
assert default_config["scraper"]["delay_between_requests"] == 1.0
|
||||
assert default_config["scraper"]["timeout"] == 30
|
||||
assert default_config["scraper"]["headless"] is True
|
||||
assert isinstance(default_config["sources"], list)
|
||||
assert len(default_config["sources"]) > 0
|
||||
|
||||
@patch('builtins.open', new_callable=mock_open, read_data="scraper:\n timeout: 60")
|
||||
@patch('pathlib.Path.exists')
|
||||
def test_load_config_existing_file(self, mock_exists, mock_file):
|
||||
"""Test loading configuration from existing file."""
|
||||
mock_exists.return_value = True
|
||||
|
||||
config_manager = ConfigManager()
|
||||
config = config_manager.load_config()
|
||||
|
||||
mock_file.assert_called_once()
|
||||
assert config["scraper"]["timeout"] == 60
|
||||
|
||||
@patch('builtins.open', new_callable=mock_open)
|
||||
@patch('pathlib.Path.exists')
|
||||
def test_load_config_create_default(self, mock_exists, mock_file):
|
||||
"""Test creating default configuration when file doesn't exist."""
|
||||
mock_exists.return_value = False
|
||||
|
||||
config_manager = ConfigManager()
|
||||
config = config_manager.load_config()
|
||||
|
||||
# Verify file was created
|
||||
mock_file.assert_called_once()
|
||||
# Verify config is default
|
||||
assert config == config_manager.default_config
|
||||
|
||||
@patch('builtins.open', new_callable=mock_open)
|
||||
def test_save_config(self, mock_file):
|
||||
"""Test saving configuration to file."""
|
||||
config_manager = ConfigManager()
|
||||
config_manager.config = {"test": "value"}
|
||||
|
||||
config_manager.save_config()
|
||||
|
||||
mock_file.assert_called_once()
|
||||
# Verify yaml.dump was called with correct arguments
|
||||
with patch('yaml.dump') as mock_dump:
|
||||
config_manager.save_config()
|
||||
mock_dump.assert_called_once()
|
||||
|
||||
def test_validate_and_merge_config(self):
|
||||
"""Test configuration validation and merging."""
|
||||
config_manager = ConfigManager()
|
||||
|
||||
# Test with partial config
|
||||
partial_config = {
|
||||
"scraper": {
|
||||
"timeout": 60
|
||||
}
|
||||
}
|
||||
config_manager.config = partial_config
|
||||
|
||||
merged = config_manager._validate_and_merge_config()
|
||||
|
||||
# Should have all sections
|
||||
assert "sources" in merged
|
||||
assert "output" in merged
|
||||
# Should have updated value
|
||||
assert merged["scraper"]["timeout"] == 60
|
||||
# Should have default values for missing keys
|
||||
assert merged["scraper"]["delay_between_requests"] == 1.0
|
||||
|
||||
def test_validate_and_merge_config_missing_required(self):
|
||||
"""Test validation fails when required sections are missing."""
|
||||
config_manager = ConfigManager()
|
||||
config_manager.config = {"invalid": "config"}
|
||||
|
||||
with pytest.raises(ValueError, match="Missing required configuration section"):
|
||||
config_manager._validate_and_merge_config()
|
||||
|
||||
def test_validate_and_merge_config_no_sources(self):
|
||||
"""Test validation fails when no sources are configured."""
|
||||
config_manager = ConfigManager()
|
||||
config_manager.config = {
|
||||
"scraper": {},
|
||||
"sources": [],
|
||||
"output": {}
|
||||
}
|
||||
|
||||
with pytest.raises(ValueError, match="At least one data source must be configured"):
|
||||
config_manager._validate_and_merge_config()
|
||||
|
||||
def test_get_with_dot_notation(self):
|
||||
"""Test getting configuration values with dot notation."""
|
||||
config_manager = ConfigManager()
|
||||
config_manager.config = {
|
||||
"scraper": {
|
||||
"timeout": 60,
|
||||
"nested": {
|
||||
"value": "test"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
assert config_manager.get("scraper.timeout") == 60
|
||||
assert config_manager.get("scraper.nested.value") == "test"
|
||||
assert config_manager.get("nonexistent", "default") == "default"
|
||||
|
||||
def test_set_with_dot_notation(self):
|
||||
"""Test setting configuration values with dot notation."""
|
||||
config_manager = ConfigManager()
|
||||
config_manager.config = {"scraper": {}}
|
||||
|
||||
config_manager.set("scraper.timeout", 60)
|
||||
config_manager.set("new.nested.value", "test")
|
||||
|
||||
assert config_manager.config["scraper"]["timeout"] == 60
|
||||
assert config_manager.config["new"]["nested"]["value"] == "test"
|
||||
|
||||
@patch.object(ConfigManager, 'load_config')
|
||||
def test_reload(self, mock_load):
|
||||
"""Test reloading configuration."""
|
||||
config_manager = ConfigManager()
|
||||
config_manager.reload()
|
||||
|
||||
mock_load.assert_called_once()
|
Reference in New Issue
Block a user