Intermediate

Testing and Documentation Generation

Writing tests and documentation is important but time-consuming. Gemini Code Assist generates both faster than you can type them - the critical skill is knowing how to verify what it generates is correct.

✍️ AI School Editorial Team · Lilly Tech Systems 📅 Published Aug 27, 2026 · Reviewed Aug 27, 2026

Generating Unit Tests

The /tests command generates unit tests for the selected code. The model reads your function's signature, existing docstring or comments, and the body, then produces a test file using the testing framework it infers from your imports and file structure. For a Python function, it will generate pytest or unittest tests. For TypeScript, it will use Jest or Vitest. For Java, it will use JUnit.

The generated tests typically cover:

  • The happy path (normal inputs, expected output)
  • Empty or null inputs (if applicable)
  • Boundary values (zero, negative numbers, maximum sizes)
  • Type errors if the language is dynamically typed
Example: Generated tests for a simple function
# Source function
def calculate_discount(price: float, discount_percent: float) -> float:
    """Apply a percentage discount to a price. Raises ValueError for invalid inputs."""
    if price < 0:
        raise ValueError("Price cannot be negative")
    if not 0 <= discount_percent <= 100:
        raise ValueError("Discount must be between 0 and 100")
    return price * (1 - discount_percent / 100)

# Generated tests (Gemini Code Assist output)
import pytest

def test_calculate_discount_standard():
    assert calculate_discount(100.0, 20.0) == pytest.approx(80.0)

def test_calculate_discount_zero_discount():
    assert calculate_discount(50.0, 0.0) == pytest.approx(50.0)

def test_calculate_discount_full_discount():
    assert calculate_discount(100.0, 100.0) == pytest.approx(0.0)

def test_calculate_discount_negative_price():
    with pytest.raises(ValueError, match="Price cannot be negative"):
        calculate_discount(-10.0, 10.0)

def test_calculate_discount_over_100_percent():
    with pytest.raises(ValueError, match="Discount must be between 0 and 100"):
        calculate_discount(100.0, 110.0)

def test_calculate_discount_negative_discount():
    with pytest.raises(ValueError, match="Discount must be between 0 and 100"):
        calculate_discount(100.0, -5.0)

This is a good starting point. But notice what is missing: fractional prices, very large prices, floating-point rounding edge cases, and a test for exactly 0% discount with a non-trivial price. Run the generated tests first, then extend them.

Requesting Edge Cases Explicitly

After running /tests, follow up in chat to ask for coverage you know is missing:

Follow-up prompts for better coverage
# Ask for domain-specific edge cases
"What edge cases specific to our discount system should be tested?
Consider: loyalty-tier discounts exceeding 100% when stacked,
prices that are fractional cents, and zero-price items."

# Ask for error path completeness
"Are there any ValueError cases in this function
that are not covered by the generated tests?"

# Ask for integration-level suggestions
"What mock objects would I need to test this function
in isolation from the database calls it triggers?"
⚠️
The hidden risk: tests that pass but do not test. AI-generated tests occasionally assert against the wrong expected value - they generate a test that matches the current (possibly buggy) behavior rather than the intended behavior. Always trace each assertion back to your specification. A test that passes does not prove the function is correct; it proves the function behaves like the model thought it should.

Generating Documentation

Gemini Code Assist generates documentation at three levels:

  • Inline comments. Right-click a complex block and select "Add comments." The model adds line or block comments explaining what the code does and why.
  • Docstrings. Select a function or class and run /doc. The model generates a language-appropriate docstring (Google style, NumPy style, JSDoc, JavaDoc) with parameter descriptions, return value, and exceptions raised.
  • README sections. In the chat panel, ask the model to generate installation, usage, or configuration sections based on your project structure and existing files.
Before: No docstring
def parse_config(path: str) -> dict:
    with open(path) as f:
        data = yaml.safe_load(f)
    validate_schema(data)
    return data
After: /doc generates Google-style docstring
def parse_config(path: str) -> dict:
    """Load and validate a YAML configuration file.

    Args:
        path: Filesystem path to the YAML configuration file.

    Returns:
        Validated configuration as a dictionary.

    Raises:
        FileNotFoundError: If the file at path does not exist.
        yaml.YAMLError: If the file is not valid YAML.
        ValidationError: If the configuration does not match the expected schema.
    """
    with open(path) as f:
        data = yaml.safe_load(f)
    validate_schema(data)
    return data

README Generation

For generating README sections, the most effective approach is a multi-step chat sequence:

  1. Open the chat panel and add @workspace context.
  2. Ask: "Describe what this project does in two sentences, based on the codebase."
  3. Ask: "List all the configuration options the project accepts, with types and defaults."
  4. Ask: "Write a getting-started section assuming the reader has Python 3.10+ installed but no other dependencies."
  5. Review and edit each output - correct project-specific details the model may have gotten wrong.
Documentation drift is real. AI-generated docs that describe the code as it was when you generated them will become wrong as the code changes. The best practice is to regenerate docs as part of the PR workflow for any function whose signature or behavior changes, not once at project launch.

Verification Checklist for AI-Generated Tests

Before merging AI-generated tests, verify each item:

  • ✅ Each test runs and passes with the current code
  • ✅ Each test fails when you deliberately break the behavior it is supposed to catch
  • ✅ Expected values match the specification, not just the current implementation
  • ✅ Mocks are configured to reflect real dependencies, not stubbed to always succeed
  • ✅ Edge cases specific to your domain are covered (not just generic boundaries)
  • ✅ Tests have descriptive names that explain what they are testing and why

Ready to Go Deeper?

Live instructor-led courses from our partners. Affiliate disclosure.