Testing

This guide covers testing strategies for applications using the YouVersion Bible Client.

Unit Testing

Mocking API Calls

Mock the client for unit tests:

from unittest.mock import AsyncMock, patch
import pytest
from youversion.clients import AsyncClient

@pytest.mark.asyncio
async def test_verse_of_the_day():
    with patch('youversion.clients.AsyncClient') as mock_client_class:
        # Create mock client
        mock_client = AsyncMock()
        mock_votd = type('Votd', (), {
            'day': 1,
            'usfm': ['JHN.3.16'],
            'image_id': None
        })()

        mock_client.verse_of_the_day.return_value = mock_votd
        mock_client_class.return_value.__aenter__.return_value = mock_client

        # Test
        async with AsyncClient() as client:
            votd = await client.verse_of_the_day()
            assert votd.day == 1
            assert votd.usfm == ['JHN.3.16']

Testing SyncClient

Test synchronous client:

from unittest.mock import patch, MagicMock
from youversion.clients import SyncClient

def test_sync_client():
    with patch('youversion.clients.SyncClient') as mock_client_class:
        mock_client = MagicMock()
        mock_votd = type('Votd', (), {
            'day': 1,
            'usfm': ['JHN.3.16']
        })()

        mock_client.verse_of_the_day.return_value = mock_votd
        mock_client_class.return_value.__enter__.return_value = mock_client

        with SyncClient() as client:
            votd = client.verse_of_the_day()
            assert votd.day == 1

Integration Testing

Testing with Real API

For integration tests, use real API calls:

import pytest
from youversion.clients import AsyncClient

@pytest.mark.integration
@pytest.mark.asyncio
async def test_real_api_call():
    """Test with real API (requires valid credentials)."""
    async with AsyncClient() as client:
        votd = await client.verse_of_the_day()
        assert votd is not None
        assert votd.day is not None
        assert votd.usfm is not None

Fixtures

Create Pytest Fixtures

Create reusable test fixtures:

import pytest
from unittest.mock import AsyncMock
from youversion.clients import AsyncClient

@pytest.fixture
def mock_async_client():
    """Create a mock AsyncClient."""
    mock_client = AsyncMock()
    mock_votd = type('Votd', (), {
        'day': 1,
        'usfm': ['JHN.3.16']
    })()
    mock_client.verse_of_the_day.return_value = mock_votd
    return mock_client

@pytest.mark.asyncio
async def test_with_fixture(mock_async_client):
    with patch('youversion.clients.AsyncClient') as mock_class:
        mock_class.return_value.__aenter__.return_value = mock_async_client
        async with AsyncClient() as client:
            votd = await client.verse_of_the_day()
            assert votd.day == 1

Test Data

Create Test Data Helpers

Create helpers for test data:

def create_mock_moment(**kwargs):
    """Create a mock moment for testing."""
    defaults = {
        'id': '123',
        'kind_id': 'highlight',
        'moment_title': 'Test Highlight',
        'time_ago': 'just now',
        'owned_by_me': True
    }
    defaults.update(kwargs)
    return type('Moment', (), defaults)()

def test_moment_processing():
    moment = create_mock_moment(id='456', moment_title='Custom')
    assert moment.id == '456'
    assert moment.moment_title == 'Custom'

Best Practices

  1. Mock External Dependencies: Always mock API calls in unit tests

  2. Test Error Cases: Test error handling and edge cases

  3. Use Fixtures: Create reusable test fixtures

  4. Separate Unit and Integration Tests: Mark integration tests appropriately

  5. Test Both Clients: Test both AsyncClient and SyncClient