Skip to content

Testing Guidelines

Specification-Style Testing

Mojentic uses a specification-style approach to testing that makes tests more readable and maintainable. This approach helps tests serve as both verification and documentation of the system's behavior.

Key Principles

  1. Descriptive Naming
  2. Use *_spec.py suffix for specification files
  3. Name test classes with Describe prefix
  4. Name test methods with should_ prefix
  5. Names should read like natural language specifications

  6. Hierarchical Organization

    class DescribeComponent:
        """Specification for the Component"""
    
        class DescribeSpecificFeature:
            """Specifications for a specific feature"""
    
            def should_behave_in_specific_way(self):
                """Test specific behavior"""
    

  7. Given-When-Then Pattern

  8. Document scenarios in docstrings using Given-When-Then
  9. Use a blank line between Given, When, and Then sections

    def should_handle_specific_case(self):
        """
        Given some initial condition
        When an action occurs
        Then expect specific outcome
        """
        initial_setup()
    
        result = perform_action()
    
        assert_expected_outcome(result)
    

  10. Test Location

  11. Co-locate tests with implementation files
  12. Use *_spec.py alongside the implementation file
  13. Example: llm_broker.py and llm_broker_spec.py

Example

class DescribeLLMBroker:
    """
    Specification for the LLMBroker class which handles interactions with Language Learning Models.
    """

    class DescribeMessageGeneration:
        """
        Specifications for generating messages through the LLM broker
        """

        def should_generate_simple_response_for_user_message(self, llm_broker):
            """
            Given a simple user message
            When generating a response
            Then it should return the LLM's response content
            """
            # Given
            messages = [LLMMessage(role=MessageRole.User, content="Hello")]

            # When
            result = llm_broker.generate(messages)

            # Then
            assert result == expected_response

Best Practices

  1. Clear Documentation
  2. Always include docstrings for test classes and methods
  3. Use Given-When-Then format in docstrings
  4. Document edge cases and special conditions

  5. Test Organization

  6. Group related tests in nested classes
  7. Use descriptive names that explain the behavior
  8. Keep test methods focused and concise

  9. Fixtures and Setup

  10. Use pytest fixtures for common setup
  11. Keep setup code minimal and clear
  12. Document fixture purpose and usage

  13. Assertions

  14. Make assertions clear and specific
  15. Include meaningful error messages
  16. Test one behavior per test method

Running Tests

# Run all tests
pytest

# Run specific specification
pytest path/to/specific_spec.py

# Show specification-style output
pytest --verbose

Additional Resources