单元测试和改进
This commit is contained in:
206
tests/test_algorithms.py
Normal file
206
tests/test_algorithms.py
Normal file
@@ -0,0 +1,206 @@
|
||||
"""
|
||||
Unit tests for algorithm modules: BaseAlgorithm, SM2Algorithm
|
||||
"""
|
||||
import pytest
|
||||
from datetime import datetime, timezone
|
||||
|
||||
from src.heurams.kernel.algorithms.base import BaseAlgorithm
|
||||
from src.heurams.kernel.algorithms.sm2 import SM2Algorithm
|
||||
from src.heurams.kernel.particles.electron import Electron
|
||||
from src.heurams.kernel.particles.orbital import Orbital
|
||||
|
||||
|
||||
class TestBaseAlgorithm:
|
||||
"""Test cases for BaseAlgorithm class."""
|
||||
|
||||
def test_base_algorithm_abstract_methods(self):
|
||||
"""Test that BaseAlgorithm cannot be instantiated directly."""
|
||||
with pytest.raises(TypeError):
|
||||
BaseAlgorithm()
|
||||
|
||||
|
||||
class TestSM2Algorithm:
|
||||
"""Test cases for SM2Algorithm class."""
|
||||
|
||||
def test_sm2_algorithm_creation(self):
|
||||
"""Test SM2Algorithm creation."""
|
||||
algorithm = SM2Algorithm()
|
||||
|
||||
assert algorithm.name == "sm2"
|
||||
assert algorithm.version == "1.0"
|
||||
|
||||
def test_sm2_calculate_interval_learning_phase(self):
|
||||
"""Test interval calculation in learning phase."""
|
||||
algorithm = SM2Algorithm()
|
||||
electron = Electron(repetitions=0)
|
||||
orbital = Orbital(learning_steps=[1, 10])
|
||||
|
||||
interval = algorithm.calculate_interval(electron, orbital, quality=3)
|
||||
|
||||
assert interval == 1 # First learning step
|
||||
|
||||
def test_sm2_calculate_interval_graduation(self):
|
||||
"""Test interval calculation when graduating."""
|
||||
algorithm = SM2Algorithm()
|
||||
electron = Electron(repetitions=1)
|
||||
orbital = Orbital(learning_steps=[1, 10], graduating_interval=1)
|
||||
|
||||
interval = algorithm.calculate_interval(electron, orbital, quality=4)
|
||||
|
||||
assert interval == 1 # Graduating interval
|
||||
|
||||
def test_sm2_calculate_interval_review_phase(self):
|
||||
"""Test interval calculation in review phase."""
|
||||
algorithm = SM2Algorithm()
|
||||
electron = Electron(ease=2.5, interval=10, repetitions=5)
|
||||
orbital = Orbital()
|
||||
|
||||
interval = algorithm.calculate_interval(electron, orbital, quality=4)
|
||||
|
||||
# Should be: 10 * 2.5 = 25
|
||||
assert interval == 25
|
||||
|
||||
def test_sm2_calculate_ease_increase(self):
|
||||
"""Test ease calculation with increase."""
|
||||
algorithm = SM2Algorithm()
|
||||
electron = Electron(ease=2.5)
|
||||
|
||||
new_ease = algorithm.calculate_ease(electron, quality=5)
|
||||
|
||||
# Should be: 2.5 + 0.1 - 0.08 + 0.02 = 2.54
|
||||
assert new_ease == pytest.approx(2.54)
|
||||
|
||||
def test_sm2_calculate_ease_decrease(self):
|
||||
"""Test ease calculation with decrease."""
|
||||
algorithm = SM2Algorithm()
|
||||
electron = Electron(ease=2.5)
|
||||
|
||||
new_ease = algorithm.calculate_ease(electron, quality=2)
|
||||
|
||||
# Should be: 2.5 + 0.1 - 0.16 + 0.02 = 2.46
|
||||
assert new_ease == pytest.approx(2.46)
|
||||
|
||||
def test_sm2_calculate_ease_minimum(self):
|
||||
"""Test ease calculation with minimum bound."""
|
||||
algorithm = SM2Algorithm()
|
||||
electron = Electron(ease=1.3) # Very low ease
|
||||
|
||||
new_ease = algorithm.calculate_ease(electron, quality=0)
|
||||
|
||||
# Should be clamped to minimum 1.3
|
||||
assert new_ease == 1.3
|
||||
|
||||
def test_sm2_calculate_repetitions_reset(self):
|
||||
"""Test repetition calculation with reset."""
|
||||
algorithm = SM2Algorithm()
|
||||
electron = Electron(repetitions=5)
|
||||
|
||||
new_repetitions = algorithm.calculate_repetitions(electron, quality=1)
|
||||
|
||||
assert new_repetitions == 0 # Reset on failure
|
||||
|
||||
def test_sm2_calculate_repetitions_increment(self):
|
||||
"""Test repetition calculation with increment."""
|
||||
algorithm = SM2Algorithm()
|
||||
electron = Electron(repetitions=2)
|
||||
|
||||
new_repetitions = algorithm.calculate_repetitions(electron, quality=3)
|
||||
|
||||
assert new_repetitions == 3 # Increment on success
|
||||
|
||||
def test_sm2_process_review_quality_1(self):
|
||||
"""Test complete review process with quality 1."""
|
||||
algorithm = SM2Algorithm()
|
||||
electron = Electron(ease=2.5, interval=10, repetitions=5)
|
||||
orbital = Orbital()
|
||||
|
||||
new_electron = algorithm.process_review(electron, orbital, 1)
|
||||
|
||||
assert new_electron.repetitions == 0
|
||||
assert new_electron.interval == 1
|
||||
assert new_electron.ease == 2.5
|
||||
|
||||
def test_sm2_process_review_quality_3(self):
|
||||
"""Test complete review process with quality 3."""
|
||||
algorithm = SM2Algorithm()
|
||||
electron = Electron(ease=2.5, interval=1, repetitions=0)
|
||||
orbital = Orbital(learning_steps=[1, 10])
|
||||
|
||||
new_electron = algorithm.process_review(electron, orbital, 3)
|
||||
|
||||
assert new_electron.repetitions == 1
|
||||
assert new_electron.interval == 1
|
||||
assert new_electron.ease == pytest.approx(2.54)
|
||||
|
||||
def test_sm2_process_review_quality_5(self):
|
||||
"""Test complete review process with quality 5."""
|
||||
algorithm = SM2Algorithm()
|
||||
electron = Electron(ease=2.5, interval=10, repetitions=5)
|
||||
orbital = Orbital()
|
||||
|
||||
new_electron = algorithm.process_review(electron, orbital, 5)
|
||||
|
||||
assert new_electron.repetitions == 6
|
||||
assert new_electron.interval == 25 # 10 * 2.5
|
||||
assert new_electron.ease == pytest.approx(2.54)
|
||||
|
||||
def test_sm2_get_next_review_date(self):
|
||||
"""Test next review date calculation."""
|
||||
algorithm = SM2Algorithm()
|
||||
electron = Electron(interval=5)
|
||||
|
||||
# Mock current time
|
||||
current_time = datetime(2024, 1, 1, 12, 0, 0, tzinfo=timezone.utc)
|
||||
|
||||
next_review = algorithm.get_next_review_date(electron, current_time)
|
||||
|
||||
expected_date = datetime(2024, 1, 6, 12, 0, 0, tzinfo=timezone.utc)
|
||||
assert next_review == expected_date
|
||||
|
||||
def test_sm2_get_next_review_date_no_interval(self):
|
||||
"""Test next review date with zero interval."""
|
||||
algorithm = SM2Algorithm()
|
||||
electron = Electron(interval=0)
|
||||
|
||||
current_time = datetime(2024, 1, 1, 12, 0, 0, tzinfo=timezone.utc)
|
||||
|
||||
next_review = algorithm.get_next_review_date(electron, current_time)
|
||||
|
||||
assert next_review == current_time
|
||||
|
||||
def test_sm2_algorithm_boundary_conditions(self):
|
||||
"""Test boundary conditions for SM2 algorithm."""
|
||||
algorithm = SM2Algorithm()
|
||||
|
||||
# Test with minimum ease
|
||||
electron = Electron(ease=1.3)
|
||||
orbital = Orbital()
|
||||
|
||||
new_electron = algorithm.process_review(electron, orbital, 0)
|
||||
assert new_electron.ease == 1.3 # Should not go below minimum
|
||||
|
||||
# Test with maximum repetitions
|
||||
electron = Electron(repetitions=100)
|
||||
new_electron = algorithm.process_review(electron, orbital, 4)
|
||||
assert new_electron.repetitions == 101 # Should continue incrementing
|
||||
|
||||
def test_sm2_algorithm_validation(self):
|
||||
"""Test input validation for SM2 algorithm."""
|
||||
algorithm = SM2Algorithm()
|
||||
electron = Electron()
|
||||
orbital = Orbital()
|
||||
|
||||
# Test invalid quality values
|
||||
with pytest.raises(ValueError):
|
||||
algorithm.process_review(electron, orbital, -1)
|
||||
|
||||
with pytest.raises(ValueError):
|
||||
algorithm.process_review(electron, orbital, 6)
|
||||
|
||||
# Test with None electron
|
||||
with pytest.raises(TypeError):
|
||||
algorithm.process_review(None, orbital, 3)
|
||||
|
||||
# Test with None orbital
|
||||
with pytest.raises(TypeError):
|
||||
algorithm.process_review(electron, None, 3)
|
||||
Reference in New Issue
Block a user