Michael Hu
Create unit tests for domain layer
48f8a08
"""Unit tests for ITranslationService interface contract."""
import pytest
from abc import ABC
from unittest.mock import Mock
from src.domain.interfaces.translation import ITranslationService
from src.domain.models.translation_request import TranslationRequest
from src.domain.models.text_content import TextContent
class TestITranslationService:
"""Test cases for ITranslationService interface contract."""
def test_interface_is_abstract(self):
"""Test that ITranslationService is an abstract base class."""
assert issubclass(ITranslationService, ABC)
# Should not be able to instantiate directly
with pytest.raises(TypeError):
ITranslationService() # type: ignore
def test_interface_has_required_method(self):
"""Test that interface defines the required abstract method."""
# Check that the method exists and is abstract
assert hasattr(ITranslationService, 'translate')
assert getattr(ITranslationService.translate, '__isabstractmethod__', False)
def test_method_signature(self):
"""Test that the method has the correct signature."""
import inspect
method = ITranslationService.translate
signature = inspect.signature(method)
# Check parameter names
params = list(signature.parameters.keys())
expected_params = ['self', 'request']
assert params == expected_params
# Check return annotation
assert signature.return_annotation == "'TextContent'"
def test_concrete_implementation_must_implement_method(self):
"""Test that concrete implementations must implement the abstract method."""
class IncompleteImplementation(ITranslationService):
pass
# Should not be able to instantiate without implementing abstract method
with pytest.raises(TypeError, match="Can't instantiate abstract class"):
IncompleteImplementation() # type: ignore
def test_concrete_implementation_with_method(self):
"""Test that concrete implementation with method can be instantiated."""
class ConcreteImplementation(ITranslationService):
def translate(self, request):
return TextContent(text="translated text", language=request.target_language)
# Should be able to instantiate
implementation = ConcreteImplementation()
assert isinstance(implementation, ITranslationService)
def test_method_contract_with_mock(self):
"""Test the method contract using a mock implementation."""
class MockImplementation(ITranslationService):
def __init__(self):
self.mock_method = Mock()
def translate(self, request):
return self.mock_method(request)
# Create test data
source_text = TextContent(text="Hello world", language="en")
request = TranslationRequest(
source_text=source_text,
target_language="es"
)
expected_result = TextContent(text="Hola mundo", language="es")
# Setup mock
implementation = MockImplementation()
implementation.mock_method.return_value = expected_result
# Call method
result = implementation.translate(request)
# Verify call and result
implementation.mock_method.assert_called_once_with(request)
assert result == expected_result
def test_interface_docstring_requirements(self):
"""Test that the interface method has proper documentation."""
method = ITranslationService.translate
assert method.__doc__ is not None
docstring = method.__doc__
# Check that docstring contains key information
assert "Translate text from source language to target language" in docstring
assert "Args:" in docstring
assert "Returns:" in docstring
assert "Raises:" in docstring
assert "TranslationFailedException" in docstring
def test_interface_type_hints(self):
"""Test that the interface uses proper type hints."""
method = ITranslationService.translate
annotations = getattr(method, '__annotations__', {})
assert 'request' in annotations
assert 'return' in annotations
# Check that type annotations are correct
assert annotations['request'] == "'TranslationRequest'"
assert annotations['return'] == "'TextContent'"
def test_multiple_implementations_possible(self):
"""Test that multiple implementations of the interface are possible."""
class NLLBImplementation(ITranslationService):
def translate(self, request):
return TextContent(text="NLLB translation", language=request.target_language)
class GoogleImplementation(ITranslationService):
def translate(self, request):
return TextContent(text="Google translation", language=request.target_language)
nllb = NLLBImplementation()
google = GoogleImplementation()
assert isinstance(nllb, ITranslationService)
assert isinstance(google, ITranslationService)
assert type(nllb) != type(google)
def test_interface_method_can_be_called_polymorphically(self):
"""Test that interface methods can be called polymorphically."""
class TestImplementation(ITranslationService):
def __init__(self, translation_prefix):
self.translation_prefix = translation_prefix
def translate(self, request):
translated_text = f"{self.translation_prefix}: {request.source_text.text}"
return TextContent(text=translated_text, language=request.target_language)
# Create different implementations
implementations = [
TestImplementation("Provider1"),
TestImplementation("Provider2")
]
# Test polymorphic usage
source_text = TextContent(text="Hello", language="en")
request = TranslationRequest(source_text=source_text, target_language="es")
results = []
for impl in implementations:
# Can call the same method on different implementations
result = impl.translate(request)
results.append(result.text)
assert results == ["Provider1: Hello", "Provider2: Hello"]
def test_interface_inheritance_chain(self):
"""Test the inheritance chain of the interface."""
# Check that it inherits from ABC
assert ABC in ITranslationService.__mro__
# Check that it's at the right position in MRO
mro = ITranslationService.__mro__
assert mro[0] == ITranslationService
assert ABC in mro
def test_method_parameter_validation_in_implementation(self):
"""Test that implementations can validate parameters."""
class ValidatingImplementation(ITranslationService):
def translate(self, request):
if not isinstance(request, TranslationRequest):
raise TypeError("request must be TranslationRequest")
# Validate that source and target languages are different
if request.effective_source_language == request.target_language:
raise ValueError("Source and target languages cannot be the same")
return TextContent(
text=f"Translated: {request.source_text.text}",
language=request.target_language
)
impl = ValidatingImplementation()
# Valid call should work
source_text = TextContent(text="Hello", language="en")
request = TranslationRequest(source_text=source_text, target_language="es")
result = impl.translate(request)
assert result.text == "Translated: Hello"
assert result.language == "es"
# Invalid parameter type should raise error
with pytest.raises(TypeError, match="request must be TranslationRequest"):
impl.translate("not a request") # type: ignore
# Same language should raise error
same_lang_text = TextContent(text="Hello", language="en")
same_lang_request = TranslationRequest(source_text=same_lang_text, target_language="en")
with pytest.raises(ValueError, match="Source and target languages cannot be the same"):
impl.translate(same_lang_request)
def test_implementation_can_handle_different_language_pairs(self):
"""Test that implementations can handle different language pairs."""
class MultiLanguageImplementation(ITranslationService):
def __init__(self):
self.translations = {
("en", "es"): {"Hello": "Hola", "world": "mundo"},
("en", "fr"): {"Hello": "Bonjour", "world": "monde"},
("es", "en"): {"Hola": "Hello", "mundo": "world"},
("fr", "en"): {"Bonjour": "Hello", "monde": "world"}
}
def translate(self, request):
source_lang = request.effective_source_language
target_lang = request.target_language
translation_dict = self.translations.get((source_lang, target_lang), {})
# Simple word-by-word translation for testing
words = request.source_text.text.split()
translated_words = [translation_dict.get(word, word) for word in words]
translated_text = " ".join(translated_words)
return TextContent(text=translated_text, language=target_lang)
impl = MultiLanguageImplementation()
# Test different language pairs
test_cases = [
("Hello world", "en", "es", "Hola mundo"),
("Hello world", "en", "fr", "Bonjour monde"),
("Hola mundo", "es", "en", "Hello world"),
("Bonjour monde", "fr", "en", "Hello world")
]
for text, source_lang, target_lang, expected in test_cases:
source_text = TextContent(text=text, language=source_lang)
request = TranslationRequest(
source_text=source_text,
target_language=target_lang,
source_language=source_lang
)
result = impl.translate(request)
assert result.text == expected
assert result.language == target_lang
def test_implementation_can_handle_auto_detect_source_language(self):
"""Test that implementations can handle auto-detection of source language."""
class AutoDetectImplementation(ITranslationService):
def translate(self, request):
# Use the effective source language (from TextContent if not explicitly set)
source_lang = request.effective_source_language
target_lang = request.target_language
# Simple mock translation based on detected language
if source_lang == "en" and target_lang == "es":
translated_text = f"ES: {request.source_text.text}"
elif source_lang == "es" and target_lang == "en":
translated_text = f"EN: {request.source_text.text}"
else:
translated_text = f"UNKNOWN: {request.source_text.text}"
return TextContent(text=translated_text, language=target_lang)
impl = AutoDetectImplementation()
# Test with explicit source language
source_text = TextContent(text="Hello", language="en")
explicit_request = TranslationRequest(
source_text=source_text,
target_language="es",
source_language="en"
)
result = impl.translate(explicit_request)
assert result.text == "ES: Hello"
assert result.language == "es"
# Test with auto-detected source language (None)
auto_request = TranslationRequest(
source_text=source_text, # language="en" in TextContent
target_language="es"
# source_language=None (default)
)
result = impl.translate(auto_request)
assert result.text == "ES: Hello" # Should use language from TextContent
assert result.language == "es"
assert auto_request.is_auto_detect_source is True