Skip to content

Instantly share code, notes, and snippets.

@spenhand
Created August 18, 2025 21:59
Show Gist options
  • Select an option

  • Save spenhand/a528373e304fd68b719ebd365034b5af to your computer and use it in GitHub Desktop.

Select an option

Save spenhand/a528373e304fd68b719ebd365034b5af to your computer and use it in GitHub Desktop.
Discord Testing Best Practices Analysis - Analysis of test changes by @night and @fozzle over the last 3 months, identifying comprehensive testing patterns and conventions used within Discord's API testing suite.

Discord Testing Best Practices Analysis

Analysis of Test Changes by @night and @fozzle (Last 3 Months)

Executive Summary

Based on analysis of 31 test file changes made by Discord developers @night (Zack) and @fozzle (Kyle Petrovich) over the past 3 months, this report identifies comprehensive testing patterns and best practices used within Discord's API testing suite. The analysis focused on specific code changes (diffs) rather than entire files to understand the testing conventions being actively adopted and refined.


Core Testing Philosophy

Discord's testing approach emphasizes comprehensive integration testing with strategic unit test components. The philosophy centers on:

  • End-to-end workflow validation while maintaining test isolation
  • Security-first testing with information disclosure prevention
  • Feature flag integration for gradual deployment testing
  • Factory-based test data generation for consistency and maintainability

Testing Patterns & Conventions

1. Test Structure & Organization

File Organization:

  • Tests mirror implementation structure: discord_api/discord/modules/[feature]/[layer]/tests/
  • Clear naming: test_[functionality]_[scenario] format
  • Comprehensive test files (200-300+ lines) covering multiple scenarios

Fixture Architecture:

@pytest.fixture()
def guild(user, recipient):
    return (
        GuildFactory.builder()
        .with_channel(GUILD_TEXT_CHANNEL_NAME, channel_type=ChannelTypes.GUILD_TEXT)
        .with_member(user=user)
        .build()
    )

2. Parametrized Testing Excellence

Comprehensive Scenario Coverage:

@pytest.mark.parametrize('require_application_authorization', (True, False))
@pytest.mark.parametrize('user_has_application_authorization', (True, False))
@pytest.mark.parametrize('action_type', [ActivityActionTypes.JOIN, ActivityActionTypes.SPECTATE])
def test_authorization_combinations(route, require_application_authorization, user_has_application_authorization, action_type):
    # Test all combinations systematically

Benefits Observed:

  • Eliminates test duplication while ensuring comprehensive coverage
  • Makes edge cases explicit and testable
  • Reduces maintenance burden through systematic testing

3. Factory Pattern Implementation

Consistent Factory Usage:

  • UserFactory(), ApplicationFactory(), GuildFactory() for core entities
  • Builder pattern for complex relationships
  • Post-creation customization through factory methods

Advanced Factory Patterns:

app = ApplicationFactory()
app.set_flag(ApplicationFlags.SOCIAL_LAYER_INTEGRATION, True)

guild = GuildFactory.builder()
    .with_channel('channel', channel_type=ChannelTypes.GUILD_TEXT)
    .with_member(user=user)
    .build()

4. Mock & Stub Strategies

Centralized Mock Setup:

@pytest.fixture(autouse=True)
def mocks(mocker: MockFixture):
    mocker.patch('discord.lib.rpc_client.discord_lobbies.create_lobby', return_value=None)
    mocker.patch('discord.lib.rpc_client.discord_lobbies.dispatch', return_value=None)
    return mocker

gRPC Integration Testing:

assert grpc_outbox.discord_presence.find('dispatch', {
    'action_type': ActionTypes.USER_ACTIVITY_ACTION,
    'user_ids': [action_user.id],
    'data': user_activity_action_serialized,
})

Spy Pattern for Validation:

check_lobby_user_spy = mocker.spy(authz, 'check_lobby_user_is_allowed')
# ... test execution
check_lobby_user_spy.assert_called_with(user)

Advanced Testing Techniques

1. Feature Flag Integration

Feature-Gated Testing:

@pytest.mark.feature_flags(APIFeatureFlags.ENABLE_USER_ACTIVITY_ACTION_DISPATCH)
@pytest.mark.enable_experiment('api_activity_action_features')
def test_feature_flag_behavior(route):
    # Test both enabled and disabled states

2. Security & Authorization Testing

Information Disclosure Prevention:

  • Systematic testing of permission boundaries
  • Validation that users only see authorized data
  • Cross-user information leakage prevention

Authorization Matrix Testing:

# Test all combinations of authorization states
if require_application_authorization and not user_has_application_authorization:
    assert response == responses.abort(FORBIDDEN, AbortMessage.APPLICATION_AUTHORIZATION_REQUIRED)
else:
    assert response == responses.ok

3. Error Handling & Edge Cases

Comprehensive Error Scenarios:

  • Rate limiting behavior validation
  • Invalid input handling
  • Network failure simulation
  • Permission boundary testing

Rate Limiting Pattern:

def test_rate_limit_behavior(route, mocker):
    # First request succeeds
    response = route(user=app.bot, json={'external_user_id': external_id})
    assert response == responses.ok
    
    # Mock rate limit exceeded
    mocker.patch('discord.lib.flask_oauth2.issue_token_rate_limit.check', return_value=100)
    response = route(user=app.bot, json={'external_user_id': external_id})
    assert response.status_code == TOO_MANY_REQUESTS

4. Integration vs Unit Test Balance

Integration Test Characteristics:

  • Full API endpoint testing with HTTP requests
  • Database persistence verification
  • Cross-service interaction validation
  • End-to-end workflow testing

Unit Test Elements:

  • Isolated authorization function testing
  • Token format validation
  • Serialization/deserialization testing
  • Business logic validation

Data Management Best Practices

1. Test Data Generation

Factory Customization:

@pytest.fixture()
def application_with_parent():
    parent = ApplicationFactory()
    return ApplicationFactory(parent_application_id=parent.id)

Faker Integration:

faker = Faker()
content = faker.pystr()  # Random content generation
external_user_id = random_hex_string(8)  # Realistic test IDs

2. Assertion Patterns

Structured Response Validation:

assert response == responses.ok
assert 'id' in response.json
assert response.json.get('activity').get('type') == ActivityActionTypes.JOIN

Deep Object Validation:

oauth2_token = OAuth2Token.get_for_access_token(response_json['access_token'])
assert oauth2_token.user_id == user.id
assert oauth2_token.application_id == application.id
assert set(oauth2_token.scopes) == OAuth2Scopes_Sets.SLAYER_INTEGRATION

Key Learnings & Recommendations

1. Consistency Standards

  • Fixture Naming: Consistent naming conventions across all test files
  • Response Assertions: Standardized response validation patterns
  • Error Messages: Uniform error handling with meaningful messages
  • Mock Organization: Centralized mock setup in fixtures

2. Test Coverage Strategies

  • Parametric Excellence: Use parametrization for comprehensive scenario coverage
  • Security Focus: Explicit testing of authorization boundaries and information disclosure
  • Feature Flag Integration: Tests that respect deployment feature states
  • Error Path Coverage: Dedicated testing of failure scenarios

3. Maintainability Features

  • Factory Evolution: Factories that can be extended without breaking existing tests
  • Mock Centralization: Shared mock fixtures reduce duplication
  • Clear Naming: Test names that explain the scenario being validated
  • Documentation: Code comments explaining complex test scenarios

4. Performance Considerations

  • Fixture Scoping: Appropriate fixture scoping to balance performance and isolation
  • Mock Strategy: Strategic mocking to maintain test speed while ensuring coverage
  • Parametrization: Efficient testing of multiple scenarios without duplicate setup

Implementation Guidelines

For New Tests:

  1. Start with parametrization for any test that has multiple valid scenarios
  2. Use factories for all test data creation to ensure consistency
  3. Mock external dependencies but preserve core business logic integration
  4. Test authorization boundaries explicitly with positive and negative cases
  5. Include feature flag testing for any functionality behind flags
  6. Validate both success and error responses with meaningful assertions

For Existing Tests:

  1. Refactor to parametrized tests where multiple similar test methods exist
  2. Consolidate mock setup into reusable fixtures
  3. Add security boundary testing where missing
  4. Ensure error path coverage for all endpoints
  5. Update factory usage instead of manual object creation

This analysis demonstrates Discord's sophisticated and mature testing practices, emphasizing comprehensive coverage, security awareness, and maintainable test architecture. The patterns identified represent industry-leading practices for API testing in distributed systems.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment