Skip to content

Commit e86fc1a

Browse files
Copilotlurenss
andcommitted
Add comprehensive test suite and test runner
Co-authored-by: lurenss <[email protected]>
1 parent ad80920 commit e86fc1a

File tree

6 files changed

+471
-0
lines changed

6 files changed

+471
-0
lines changed

run_tests.py

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
#!/usr/bin/env python
2+
"""
3+
Test runner for ScrapeGraphAI Elasticsearch Demo
4+
5+
This script runs all unit tests and reports the results.
6+
"""
7+
8+
import sys
9+
import os
10+
11+
# Add src to path
12+
sys.path.insert(0, os.path.abspath(os.path.dirname(__file__)))
13+
14+
from tests import test_config, test_models, test_scraper
15+
16+
17+
def run_all_tests():
18+
"""Run all test modules"""
19+
print("=" * 60)
20+
print("ScrapeGraphAI Elasticsearch Demo - Test Suite")
21+
print("=" * 60)
22+
print()
23+
24+
test_modules = [
25+
("Configuration Tests", test_config),
26+
("Model Tests", test_models),
27+
("Scraper Tests", test_scraper),
28+
]
29+
30+
total_passed = 0
31+
total_failed = 0
32+
33+
for name, module in test_modules:
34+
print(f"\n{'=' * 60}")
35+
print(f"{name}")
36+
print("=" * 60)
37+
38+
try:
39+
# Get all test functions from the module
40+
test_functions = [
41+
getattr(module, func)
42+
for func in dir(module)
43+
if func.startswith('test_') and callable(getattr(module, func))
44+
]
45+
46+
passed = 0
47+
failed = 0
48+
49+
for test_func in test_functions:
50+
try:
51+
test_func()
52+
passed += 1
53+
except AssertionError as e:
54+
print(f"✗ {test_func.__name__} failed: {e}")
55+
failed += 1
56+
except Exception as e:
57+
print(f"✗ {test_func.__name__} error: {e}")
58+
failed += 1
59+
60+
total_passed += passed
61+
total_failed += failed
62+
63+
print(f"\nResults: {passed} passed, {failed} failed")
64+
65+
except Exception as e:
66+
print(f"Error loading test module: {e}")
67+
total_failed += 1
68+
69+
# Final summary
70+
print("\n" + "=" * 60)
71+
print("FINAL RESULTS")
72+
print("=" * 60)
73+
print(f"Total tests passed: {total_passed}")
74+
print(f"Total tests failed: {total_failed}")
75+
76+
if total_failed == 0:
77+
print("\n✓ All tests passed!")
78+
return 0
79+
else:
80+
print(f"\n{total_failed} test(s) failed")
81+
return 1
82+
83+
84+
if __name__ == "__main__":
85+
sys.exit(run_all_tests())

tests/README.md

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
# Tests
2+
3+
This directory contains unit tests for the ScrapeGraphAI Elasticsearch Demo project.
4+
5+
## Running Tests
6+
7+
### Run All Tests
8+
9+
```bash
10+
python run_tests.py
11+
```
12+
13+
### Run Individual Test Modules
14+
15+
```bash
16+
# Configuration tests
17+
python tests/test_config.py
18+
19+
# Model tests
20+
python tests/test_models.py
21+
22+
# Scraper tests
23+
python tests/test_scraper.py
24+
```
25+
26+
## Test Coverage
27+
28+
### test_config.py
29+
Tests for configuration management:
30+
- Loading configuration from environment variables
31+
- Elasticsearch URL generation
32+
- Configuration with credentials
33+
34+
### test_models.py
35+
Tests for data models:
36+
- Product model creation
37+
- Elasticsearch document conversion
38+
- ProductComparison functionality
39+
- Edge cases (e.g., products without ratings)
40+
41+
### test_scraper.py
42+
Tests for the marketplace scraper:
43+
- Scraper initialization
44+
- Mock product scraping
45+
- Search results scraping
46+
- Price extraction from various formats
47+
- Product ID extraction from URLs
48+
49+
## Notes
50+
51+
- These tests use mock data and do not require Elasticsearch to be running
52+
- The tests verify the core functionality without making actual web requests
53+
- All tests should pass in a clean environment with dependencies installed
54+
55+
## Dependencies
56+
57+
Make sure you have installed all required dependencies:
58+
59+
```bash
60+
pip install -r requirements.txt
61+
```

tests/__init__.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
"""
2+
Test package for ScrapeGraphAI Elasticsearch Demo
3+
"""

tests/test_config.py

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
"""
2+
Unit tests for configuration
3+
"""
4+
5+
import sys
6+
import os
7+
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
8+
9+
from src.scrapegraph_demo import Config
10+
11+
12+
def test_config_from_env():
13+
"""Test loading configuration from environment"""
14+
config = Config.from_env()
15+
16+
assert config is not None
17+
assert config.elasticsearch_host is not None
18+
assert config.elasticsearch_port > 0
19+
assert config.elasticsearch_scheme in ["http", "https"]
20+
print("✓ test_config_from_env passed")
21+
22+
23+
def test_elasticsearch_url():
24+
"""Test Elasticsearch URL generation"""
25+
config = Config(
26+
elasticsearch_host="localhost",
27+
elasticsearch_port=9200,
28+
elasticsearch_scheme="http",
29+
elasticsearch_username=None,
30+
elasticsearch_password=None,
31+
scrapegraphai_api_key=None,
32+
openai_api_key=None
33+
)
34+
35+
assert config.elasticsearch_url == "http://localhost:9200"
36+
print("✓ test_elasticsearch_url passed")
37+
38+
39+
def test_config_with_credentials():
40+
"""Test configuration with credentials"""
41+
config = Config(
42+
elasticsearch_host="localhost",
43+
elasticsearch_port=9200,
44+
elasticsearch_scheme="https",
45+
elasticsearch_username="user",
46+
elasticsearch_password="pass",
47+
scrapegraphai_api_key="test_key",
48+
openai_api_key="openai_key"
49+
)
50+
51+
assert config.elasticsearch_username == "user"
52+
assert config.elasticsearch_password == "pass"
53+
assert config.scrapegraphai_api_key == "test_key"
54+
assert config.openai_api_key == "openai_key"
55+
assert config.elasticsearch_url == "https://localhost:9200"
56+
print("✓ test_config_with_credentials passed")
57+
58+
59+
if __name__ == "__main__":
60+
print("Running config tests...\n")
61+
test_config_from_env()
62+
test_elasticsearch_url()
63+
test_config_with_credentials()
64+
print("\n✓ All tests passed!")

tests/test_models.py

Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
"""
2+
Unit tests for data models
3+
"""
4+
5+
import sys
6+
import os
7+
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
8+
9+
from datetime import datetime
10+
from src.scrapegraph_demo.models import Product, ProductComparison
11+
12+
13+
def test_product_creation():
14+
"""Test creating a Product instance"""
15+
product = Product(
16+
product_id="TEST123",
17+
name="Test Product",
18+
price=99.99,
19+
currency="USD",
20+
url="https://example.com/product/TEST123",
21+
marketplace="TestMarket",
22+
description="A test product",
23+
brand="TestBrand",
24+
category="Electronics",
25+
rating=4.5,
26+
review_count=100,
27+
availability="In Stock"
28+
)
29+
30+
assert product.product_id == "TEST123"
31+
assert product.name == "Test Product"
32+
assert product.price == 99.99
33+
assert product.marketplace == "TestMarket"
34+
print("✓ test_product_creation passed")
35+
36+
37+
def test_product_to_elasticsearch_doc():
38+
"""Test converting Product to Elasticsearch document"""
39+
product = Product(
40+
product_id="TEST123",
41+
name="Test Product",
42+
price=99.99,
43+
currency="USD",
44+
url="https://example.com/product/TEST123",
45+
marketplace="TestMarket"
46+
)
47+
48+
doc = product.to_elasticsearch_doc()
49+
assert isinstance(doc, dict)
50+
assert doc["product_id"] == "TEST123"
51+
assert doc["name"] == "Test Product"
52+
assert "scraped_at" in doc
53+
print("✓ test_product_to_elasticsearch_doc passed")
54+
55+
56+
def test_product_comparison():
57+
"""Test ProductComparison functionality"""
58+
products = [
59+
Product(
60+
product_id="P1",
61+
name="Product 1",
62+
price=50.0,
63+
currency="USD",
64+
url="https://example.com/p1",
65+
marketplace="Amazon",
66+
rating=4.5,
67+
review_count=100
68+
),
69+
Product(
70+
product_id="P2",
71+
name="Product 2",
72+
price=30.0,
73+
currency="USD",
74+
url="https://example.com/p2",
75+
marketplace="eBay",
76+
rating=4.8,
77+
review_count=200
78+
),
79+
Product(
80+
product_id="P3",
81+
name="Product 3",
82+
price=70.0,
83+
currency="USD",
84+
url="https://example.com/p3",
85+
marketplace="Amazon",
86+
rating=4.2,
87+
review_count=50
88+
),
89+
]
90+
91+
comparison = ProductComparison(
92+
query="test query",
93+
products=products
94+
)
95+
96+
# Test price range
97+
min_price, max_price = comparison.get_price_range()
98+
assert min_price == 30.0
99+
assert max_price == 70.0
100+
101+
# Test cheapest
102+
cheapest = comparison.get_cheapest()
103+
assert cheapest.product_id == "P2"
104+
assert cheapest.price == 30.0
105+
106+
# Test best rated
107+
best_rated = comparison.get_best_rated()
108+
assert best_rated.product_id == "P2"
109+
assert best_rated.rating == 4.8
110+
111+
# Test grouping
112+
grouped = comparison.group_by_marketplace()
113+
assert len(grouped["Amazon"]) == 2
114+
assert len(grouped["eBay"]) == 1
115+
116+
print("✓ test_product_comparison passed")
117+
118+
119+
def test_product_comparison_no_ratings():
120+
"""Test ProductComparison with products that have no ratings"""
121+
products = [
122+
Product(
123+
product_id="P1",
124+
name="Product 1",
125+
price=50.0,
126+
currency="USD",
127+
url="https://example.com/p1",
128+
marketplace="Amazon"
129+
),
130+
Product(
131+
product_id="P2",
132+
name="Product 2",
133+
price=30.0,
134+
currency="USD",
135+
url="https://example.com/p2",
136+
marketplace="eBay"
137+
),
138+
]
139+
140+
comparison = ProductComparison(
141+
query="test query",
142+
products=products
143+
)
144+
145+
# Should return None when no products have ratings
146+
best_rated = comparison.get_best_rated()
147+
assert best_rated is None
148+
149+
print("✓ test_product_comparison_no_ratings passed")
150+
151+
152+
if __name__ == "__main__":
153+
print("Running model tests...\n")
154+
test_product_creation()
155+
test_product_to_elasticsearch_doc()
156+
test_product_comparison()
157+
test_product_comparison_no_ratings()
158+
print("\n✓ All tests passed!")

0 commit comments

Comments
 (0)