Testowanie - emielregis2/SmartFlowAI GitHub Wiki
Testowanie - SmartFlowAI
Poznaj kompletny system testowania SmartFlowAI - od testów jednostkowych po testy end-to-end! 🧪
🎯 Przegląd testowania
SmartFlowAI używa wielopoziomowej strategii testowania zapewniającej wysoką jakość kodu:
┌─────────────────┐
│ E2E Tests │ ← Testy całej aplikacji
├─────────────────┤
│ Integration │ ← Testy integracji z API
├─────────────────┤
│ Unit Tests │ ← Testy jednostkowe funkcji
└─────────────────┘
📊 Statystyki testów
Typ testu | Pliki | Testy | Pokrycie | Czas wykonania |
---|---|---|---|---|
Jednostkowe | 3 | 25+ | 80%+ | <30s |
Integracyjne | 2 | 15+ | 70%+ | 1-2min |
End-to-End | 1 | 10+ | 90%+ | 3-5min |
Produkcyjne | 1 | 20+ | 95%+ | 2-3min |
🧪 Typy testów
1. Testy jednostkowe (Unit Tests)
test_app.py
- Podstawowe testy
def test_validate_process_input():
"""Test walidacji danych wejściowych procesu"""
# Test poprawnych danych
valid, msg = validate_process_input("Test proces", "Szczegółowy opis procesu")
assert valid == True
# Test niepoprawnych danych
valid, msg = validate_process_input("", "Opis")
assert valid == False
assert "minimum 3 znaki" in msg
test_simple_working.py
- Testy funkcjonalności
def test_password_hashing():
"""Test hashowania haseł"""
password = "test123456"
hashed = hash_password(password)
assert verify_password(password, hashed) == True
assert verify_password("wrong", hashed) == False
def test_openai_prompt_generation():
"""Test generowania promptów dla AI"""
prompt = create_analysis_prompt(
title="Test proces",
description="Opis procesu",
depth="Podstawowa",
company_size="1-10 osób",
industry="IT",
budget="500-1000 zł/mies"
)
assert "Test proces" in prompt
assert "Podstawowa" in prompt
2. Testy integracyjne (Integration Tests)
test_comprehensive.py
- Testy z bazą danych
def test_supabase_connection():
"""Test połączenia z Supabase"""
supabase = init_supabase()
assert supabase is not None
# Test zapytania do bazy
result = supabase.table('users').select('*').limit(1).execute()
assert result.data is not None
def test_user_authentication():
"""Test autentykacji użytkowników"""
# Test logowania z prawidłowymi danymi
user = authenticate_user("[email protected]", "test123456")
assert user is not None
assert user['email'] == "[email protected]"
# Test logowania z nieprawidłowymi danymi
user = authenticate_user("[email protected]", "wrong_password")
assert user is None
test_enhanced_analysis.py
- Testy analizy AI
def test_openai_api_connection():
"""Test połączenia z OpenAI API"""
client = init_openai()
assert client is not None
# Test prostego zapytania
response = client.chat.completions.create(
model="gpt-4o",
messages=[{"role": "user", "content": "Test"}],
max_tokens=10
)
assert response.choices[0].message.content is not None
def test_process_analysis():
"""Test analizy procesu przez AI"""
analysis = analyze_process_with_ai(
title="Test proces",
description="Szczegółowy opis procesu testowego",
depth="Podstawowa",
company_size="1-10 osób",
industry="IT",
budget="500-1000 zł/mies"
)
assert analysis is not None
assert len(analysis) > 100 # Analiza powinna być szczegółowa
3. Testy end-to-end (E2E Tests)
test_e2e.py
- Pełny przepływ aplikacji
def test_complete_user_workflow():
"""Test kompletnego przepływu użytkownika"""
# 1. Logowanie
user = authenticate_user("[email protected]", "test123456")
assert user is not None
# 2. Dodanie procesu
process_data = {
'title': 'E2E Test Process',
'description': 'Proces testowy dla testów end-to-end',
'user_id': user['id']
}
saved_process = save_process(process_data)
assert saved_process is not None
# 3. Analiza AI
analysis = analyze_process_with_ai(
title=process_data['title'],
description=process_data['description'],
depth="Podstawowa",
company_size="1-10 osób",
industry="IT",
budget="500-1000 zł/mies"
)
assert analysis is not None
# 4. Aktualizacja procesu z analizą
updated_process = update_process(saved_process['id'], {'ai_analysis': analysis})
assert updated_process is not None
# 5. Pobranie procesów użytkownika
user_processes = get_processes(user['id'])
assert len(user_processes) > 0
# 6. Usunięcie procesu (cleanup)
delete_result = delete_process(saved_process['id'])
assert delete_result == True
4. Testy produkcyjne (Production Tests)
test_production_ready.py
- Testy gotowości produkcyjnej
def test_environment_variables():
"""Test czy wszystkie wymagane zmienne środowiskowe są ustawione"""
required_vars = [
'SUPABASE_URL',
'SUPABASE_ANON_KEY',
'SUPABASE_SERVICE_ROLE_KEY',
'OPENAI_API_KEY'
]
for var in required_vars:
value = os.getenv(var)
assert value is not None, f"Zmienna {var} nie jest ustawiona"
assert len(value) > 10, f"Zmienna {var} wydaje się niepoprawna"
def test_database_schema():
"""Test czy schemat bazy danych jest poprawny"""
supabase = init_supabase()
# Test tabeli users
users = supabase.table('users').select('*').limit(1).execute()
assert users.data is not None
# Test tabeli business_processes
processes = supabase.table('business_processes').select('*').limit(1).execute()
assert processes.data is not None
def test_api_rate_limits():
"""Test limitów API"""
# Test czy OpenAI API nie przekracza limitów
start_time = time.time()
for i in range(3):
response = openai.ChatCompletion.create(
model="gpt-4o",
messages=[{"role": "user", "content": f"Test {i}"}],
max_tokens=10
)
assert response.choices[0].message.content is not None
elapsed_time = time.time() - start_time
assert elapsed_time < 30, "API calls took too long"
🚀 Uruchamianie testów
Przygotowanie środowiska
# Aktywuj środowisko wirtualne
.venv\Scripts\activate # Windows
source .venv/bin/activate # Linux/macOS
# Zainstaluj zależności testowe
pip install -r requirements-dev.txt
# Ustaw zmienne środowiskowe testowe
export SUPABASE_URL="https://test-projekt.supabase.co"
export OPENAI_API_KEY="sk-test-key"
Uruchamianie poszczególnych testów
Testy podstawowe
# Wszystkie testy podstawowe
pytest test_app.py -v
# Konkretny test
pytest test_app.py::test_validate_process_input -v
# Z pokryciem kodu
pytest test_app.py --cov=streamlit_app --cov-report=html
Testy integracyjne
# Testy z bazą danych (wymagają konfiguracji Supabase)
pytest test_comprehensive.py -v
# Testy analizy AI (wymagają klucza OpenAI)
pytest test_enhanced_analysis.py -v
Testy end-to-end
# Pełny przepływ aplikacji
pytest test_e2e.py -v
# Z szczegółowymi logami
pytest test_e2e.py -v -s --log-cli-level=INFO
Testy produkcyjne
# Sprawdzenie gotowości do produkcji
pytest test_production_ready.py -v
# Tylko krytyczne testy
pytest test_production_ready.py -k "critical" -v
Uruchamianie wszystkich testów
# Wszystkie testy
pytest -v
# Z raportem pokrycia
pytest --cov=streamlit_app --cov-report=html --cov-report=term
# Tylko szybkie testy (bez AI)
pytest -m "not slow" -v
# Równoległe wykonanie
pytest -n 4 -v # 4 procesy równolegle
📋 Konfiguracja testów
pytest.ini
- Konfiguracja pytest
[tool:pytest]
testpaths = .
python_files = test_*.py
python_classes = Test*
python_functions = test_*
addopts =
-v
--tb=short
--strict-markers
--disable-warnings
--color=yes
markers =
slow: marks tests as slow (deselect with '-m "not slow"')
integration: marks tests as integration tests
e2e: marks tests as end-to-end tests
production: marks tests as production readiness tests
Zmienne środowiskowe testowe
# .env.test
SUPABASE_URL=https://test-projekt.supabase.co
SUPABASE_ANON_KEY=test_anon_key
SUPABASE_SERVICE_ROLE_KEY=test_service_key
OPENAI_API_KEY=sk-test-key
DEMO_MODE=true
🔧 Narzędzia testowe
Pytest - Framework testowy
# Instalacja
pip install pytest pytest-cov pytest-xdist
# Podstawowe użycie
pytest # Wszystkie testy
pytest test_app.py # Konkretny plik
pytest -k "test_auth" # Testy zawierające "auth"
pytest -x # Stop po pierwszym błędzie
Coverage - Pokrycie kodu
# Raport pokrycia
pytest --cov=streamlit_app
# HTML raport
pytest --cov=streamlit_app --cov-report=html
# Otwórz htmlcov/index.html w przeglądarce
# Raport XML (dla CI/CD)
pytest --cov=streamlit_app --cov-report=xml
Fixtures - Dane testowe
# conftest.py
import pytest
@pytest.fixture
def test_user():
"""Fixture z danymi testowego użytkownika"""
return {
'email': '[email protected]',
'password': 'test123456',
'full_name': 'Test User'
}
@pytest.fixture
def test_process():
"""Fixture z danymi testowego procesu"""
return {
'title': 'Test Process',
'description': 'Szczegółowy opis testowego procesu biznesowego',
'analysis_depth': 'Podstawowa',
'company_size': '1-10 osób',
'industry': 'IT',
'budget_range': '500-1000 zł/mies'
}
🐛 Debugging testów
Uruchamianie z debuggerem
# Z pdb debuggerem
pytest --pdb test_app.py
# Z ipdb (lepszy debugger)
pip install ipdb
pytest --pdb --pdbcls=IPython.terminal.debugger:Pdb test_app.py
# Tylko przy błędach
pytest --pdb-trace test_app.py
Logi w testach
import logging
def test_with_logging():
"""Test z logowaniem"""
logger = logging.getLogger(__name__)
logger.info("Starting test")
# Twój kod testowy
result = some_function()
logger.info(f"Result: {result}")
assert result is not None
Uruchamianie z logami
# Pokaż logi w testach
pytest -s --log-cli-level=INFO test_app.py
# Zapisz logi do pliku
pytest --log-file=tests.log test_app.py
📊 Raporty testów
HTML Report
# Generuj raport HTML
pytest --html=report.html --self-contained-html
# Z pokryciem kodu
pytest --cov=streamlit_app --cov-report=html --html=report.html
JUnit XML (dla CI/CD)
# Raport XML dla Jenkins/GitHub Actions
pytest --junitxml=test-results.xml
# Z pokryciem
pytest --cov=streamlit_app --cov-report=xml --junitxml=test-results.xml
Allure Reports (zaawansowane)
# Instalacja
pip install allure-pytest
# Generowanie danych
pytest --alluredir=allure-results
# Serwowanie raportu
allure serve allure-results
✅ Best Practices testowania
1. Struktura testów (AAA Pattern)
def test_user_authentication():
# Arrange - Przygotowanie danych
email = "[email protected]"
password = "test123456"
# Act - Wykonanie akcji
user = authenticate_user(email, password)
# Assert - Sprawdzenie wyników
assert user is not None
assert user['email'] == email
2. Nazewnictwo testów
# ✅ Dobre nazwy
def test_should_return_user_when_credentials_are_valid():
def test_should_raise_exception_when_email_is_empty():
def test_should_generate_pdf_with_all_processes():
# ❌ Złe nazwy
def test_user():
def test_login():
def test_pdf():
3. Izolacja testów
@pytest.fixture(autouse=True)
def cleanup_database():
"""Automatyczne czyszczenie bazy po każdym teście"""
yield # Test się wykonuje
# Cleanup po teście
supabase.table('business_processes').delete().neq('id', '').execute()
4. Mockowanie zewnętrznych serwisów
from unittest.mock import patch, MagicMock
@patch('openai.ChatCompletion.create')
def test_ai_analysis_with_mock(mock_openai):
"""Test analizy AI z mockiem OpenAI"""
# Arrange
mock_response = MagicMock()
mock_response.choices[0].message.content = "Mocked AI response"
mock_openai.return_value = mock_response
# Act
result = analyze_process_with_ai("Test", "Description", "Basic", "1-10", "IT", "500-1000")
# Assert
assert result == "Mocked AI response"
mock_openai.assert_called_once()
🚨 Troubleshooting testów
Częste problemy
Problem: "ModuleNotFoundError"
# Rozwiązanie: Dodaj ścieżkę do PYTHONPATH
export PYTHONPATH="${PYTHONPATH}:$(pwd)"
pytest test_app.py
Problem: "Database connection failed"
# Sprawdź zmienne środowiskowe
echo $SUPABASE_URL
echo $SUPABASE_ANON_KEY
# Uruchom z debug mode
pytest -s --log-cli-level=DEBUG test_comprehensive.py
Problem: "OpenAI API rate limit"
# Użyj mocków dla testów jednostkowych
@patch('openai.ChatCompletion.create')
def test_with_mock(mock_openai):
# Test bez prawdziwego API call
Problem: "Tests are too slow"
# Uruchom tylko szybkie testy
pytest -m "not slow"
# Równoległe wykonanie
pip install pytest-xdist
pytest -n 4 # 4 procesy
📈 Metryki jakości
Cele pokrycia kodu
- Funkcje główne: 95%+
- Logika biznesowa: 90%+
- Obsługa błędów: 80%+
- UI komponenty: 70%+
Kryteria akceptacji
- ✅ Wszystkie testy przechodzą
- ✅ Pokrycie kodu > 80%
- ✅ Brak błędów krytycznych
- ✅ Czas wykonania < 5 minut
- ✅ Zero podatności bezpieczeństwa
Następny krok: CI/CD - poznaj automatyzację testów i deploymentu w GitHub Actions.