db85a174b9
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Has been skipped
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / Validate - Code Quality (push) Failing after 1m39s
CI/CD Pipeline / Validate - Type Check (mypy) (push) Successful in 1m11s
CI/CD Pipeline / Validate - Migration (alembic) (push) Successful in 1m4s
CI/CD Pipeline / Unit Tests (push) Successful in 6m4s
CI/CD Pipeline / Integration Tests (push) Successful in 2m20s
CI/CD Pipeline / Frontend Lint (push) Successful in 36s
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 1m48s
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
CI/CD Pipeline / Build Staging API Image (push) Failing after 9m40s
CI/CD Pipeline / Build Staging Web Image (push) Successful in 1m16s
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 2m52s
CI/CD Pipeline / Build Production API Image (push) Has been skipped
CI/CD Pipeline / Build Production Web Image (push) Has been skipped
CI/CD Pipeline / Build Production Worker Image (push) Has been skipped
CI/CD Pipeline / Deploy Production (push) Has been skipped
CI/CD Pipeline / Production Browser E2E (push) Has been skipped
CI/CD Pipeline / Staging E2E Tests (push) Has been skipped
CI/CD Pipeline / Staging API Integration Tests (push) Has been skipped
CI/CD Pipeline / ACR Image Cleanup (push) Has been skipped
132 lines
4.0 KiB
Python
Executable File
132 lines
4.0 KiB
Python
Executable File
"""领域层通用异常单元测试."""
|
|
|
|
import pytest
|
|
|
|
from packages.domain.exceptions import (
|
|
DomainError,
|
|
NotFoundError,
|
|
QuotaExceededError,
|
|
ValidationError,
|
|
)
|
|
|
|
|
|
class TestDomainError:
|
|
"""DomainError 基类测试"""
|
|
|
|
def test_is_exception(self):
|
|
"""DomainError 是 Exception 的子类"""
|
|
assert issubclass(DomainError, Exception)
|
|
|
|
def test_can_raise_and_catch(self):
|
|
"""可以抛出和捕获"""
|
|
with pytest.raises(DomainError):
|
|
raise DomainError("something went wrong")
|
|
|
|
def test_message(self):
|
|
"""异常消息正确"""
|
|
err = DomainError("test message")
|
|
assert str(err) == "test message"
|
|
|
|
|
|
class TestNotFoundError:
|
|
"""NotFoundError 测试"""
|
|
|
|
def test_is_domain_error(self):
|
|
"""NotFoundError 继承自 DomainError"""
|
|
assert issubclass(NotFoundError, DomainError)
|
|
|
|
def test_can_raise_as_domain_error(self):
|
|
"""可以作为 DomainError 捕获"""
|
|
with pytest.raises(DomainError):
|
|
raise NotFoundError("resource not found")
|
|
|
|
def test_default_message(self):
|
|
"""无参构造"""
|
|
err = NotFoundError()
|
|
assert isinstance(err, NotFoundError)
|
|
|
|
def test_custom_message(self):
|
|
"""自定义消息"""
|
|
err = NotFoundError("user 123 not found")
|
|
assert str(err) == "user 123 not found"
|
|
|
|
|
|
class TestValidationError:
|
|
"""ValidationError 测试"""
|
|
|
|
def test_is_domain_error(self):
|
|
"""ValidationError 继承自 DomainError"""
|
|
assert issubclass(ValidationError, DomainError)
|
|
|
|
def test_can_raise_as_domain_error(self):
|
|
"""可以作为 DomainError 捕获"""
|
|
with pytest.raises(DomainError):
|
|
raise ValidationError("invalid input")
|
|
|
|
def test_custom_message(self):
|
|
"""自定义消息"""
|
|
err = ValidationError("duration must be positive")
|
|
assert str(err) == "duration must be positive"
|
|
|
|
|
|
class TestQuotaExceededError:
|
|
"""QuotaExceededError 测试"""
|
|
|
|
def test_is_domain_error(self):
|
|
"""QuotaExceededError 继承自 DomainError"""
|
|
assert issubclass(QuotaExceededError, DomainError)
|
|
|
|
def test_can_raise_as_domain_error(self):
|
|
"""可以作为 DomainError 捕获"""
|
|
with pytest.raises(DomainError):
|
|
raise QuotaExceededError("storage", 1024.0, 2048.0)
|
|
|
|
def test_stores_dimension_limit_used(self):
|
|
"""保存 dimension、limit、used 属性"""
|
|
err = QuotaExceededError("storage_mb", 1024.0, 1500.0)
|
|
assert err.dimension == "storage_mb"
|
|
assert err.limit == 1024.0
|
|
assert err.used == 1500.0
|
|
|
|
def test_error_message_format(self):
|
|
"""异常消息格式正确"""
|
|
err = QuotaExceededError("storage_mb", 1024.0, 1500.0)
|
|
msg = str(err)
|
|
assert "storage_mb" in msg
|
|
assert "1500.0" in msg
|
|
assert "1024.0" in msg
|
|
assert "Quota exceeded" in msg
|
|
|
|
def test_integer_values(self):
|
|
"""整数值也能正常工作"""
|
|
err = QuotaExceededError("projects", 10, 15)
|
|
assert err.dimension == "projects"
|
|
assert err.limit == 10
|
|
assert err.used == 15
|
|
|
|
def test_zero_limit(self):
|
|
"""限制为 0 时也能正常工作"""
|
|
err = QuotaExceededError("custom_templates", 0, 1)
|
|
assert err.limit == 0
|
|
assert err.used == 1
|
|
|
|
|
|
class TestExceptionHierarchy:
|
|
"""异常继承关系测试"""
|
|
|
|
def test_all_are_domain_errors(self):
|
|
"""所有异常都可以作为 DomainError 捕获"""
|
|
errors = [
|
|
NotFoundError(),
|
|
ValidationError("bad"),
|
|
QuotaExceededError("x", 10.0, 20.0),
|
|
]
|
|
for err in errors:
|
|
assert isinstance(err, DomainError)
|
|
|
|
def test_distinct_types(self):
|
|
"""不同异常类型可以区分"""
|
|
assert not issubclass(NotFoundError, ValidationError)
|
|
assert not issubclass(ValidationError, QuotaExceededError)
|
|
assert not issubclass(NotFoundError, QuotaExceededError)
|