|
1 | | -# Testing Your Notion Integrations |
2 | | - |
3 | | -> **⚠️ WORK IN PROGRESS**: This documentation is being actively developed and may be incomplete or subject to change. |
| 1 | +# Testing Guide |
4 | 2 |
|
5 | 3 | ## Overview |
6 | 4 |
|
7 | | -This guide covers strategies for testing code that uses the Kotlin Notion Client, including how the library's own tests are structured. |
| 5 | +This guide explains how the Kotlin Notion Client organizes its tests and how to run them. The library has comprehensive test coverage with fast unit tests and real API integration tests. |
| 6 | + |
| 7 | +## Test Organization |
| 8 | + |
| 9 | +### Unit Tests (`src/test/kotlin/unit/`) |
| 10 | +- **Fast**: ~481 tests run in ~200ms |
| 11 | +- **No API calls**: Use mock responses from official Notion API samples |
| 12 | +- **Tagged**: `@Tags("Unit")` |
8 | 13 |
|
9 | | -## How This Library Handles Tests |
| 14 | +### Integration Tests (`src/test/kotlin/integration/`) |
| 15 | +- **Real API**: Make actual requests to Notion |
| 16 | +- **Require setup**: Need environment variables |
| 17 | +- **Tagged**: `@Tags("Integration", "RequiresApi")` or with `"Slow"` for long-running tests |
| 18 | +- **Protected**: Won't run without `NOTION_RUN_INTEGRATION_TESTS=true` |
10 | 19 |
|
11 | | -This library uses a unified test approach where integration tests are controlled by environment variables: |
| 20 | +### Example Tests (`src/test/kotlin/examples/`) |
| 21 | +- **Documentation examples**: Validate code in docs actually works |
| 22 | +- **Also integration tests**: Tagged with `@Tags("Integration", "RequiresApi", "Examples")` |
| 23 | + |
| 24 | +## The Master Switch |
| 25 | + |
| 26 | +All integration tests check this environment variable: |
12 | 27 |
|
13 | 28 | ```kotlin |
14 | | -// Integration tests check env vars and skip if not set |
15 | | -if (!integrationTestEnvVarsAreSet()) { |
16 | | - "!(Skipped) Integration test" { |
17 | | - println("⏭️ Skipping - missing environment variables") |
| 29 | +// From src/test/kotlin/integration/Util.kt |
| 30 | +fun integrationTestEnvVarsAreSet(...): Boolean { |
| 31 | + if (System.getenv("NOTION_RUN_INTEGRATION_TESTS")?.lowercase() != "true") { |
| 32 | + return false // Integration tests skip |
18 | 33 | } |
19 | | -} else { |
20 | | - // actual test code |
| 34 | + // ... check other required env vars |
21 | 35 | } |
22 | 36 | ``` |
23 | 37 |
|
24 | | -### Running Tests |
| 38 | +**This is your safety**: Integration tests never run without explicit opt-in via environment variable. |
| 39 | + |
| 40 | +## Running Tests |
| 41 | + |
| 42 | +### Fast development (recommended) |
25 | 43 |
|
26 | 44 | ```bash |
27 | | -# Run unit tests only (integration tests automatically skip) |
| 45 | +# Run only unit tests - fast, no API calls |
28 | 46 | ./gradlew test |
29 | 47 |
|
30 | | -# Run with integration tests enabled |
| 48 | +# All ~481 unit tests pass in ~200ms |
| 49 | +``` |
| 50 | + |
| 51 | +### Running specific integration tests |
| 52 | + |
| 53 | +```bash |
| 54 | +# Set up once per session |
31 | 55 | export NOTION_RUN_INTEGRATION_TESTS=true |
32 | | -export NOTION_API_TOKEN="secret_..." |
33 | | -export NOTION_TEST_PAGE_ID="page-id" |
| 56 | +export NOTION_API_TOKEN="secret_your_token" |
| 57 | +export NOTION_TEST_PAGE_ID="your-page-id" |
| 58 | + |
| 59 | +# Run one integration test |
| 60 | +./gradlew test --tests "*PagesIntegrationTest" |
| 61 | +``` |
34 | 62 |
|
35 | | -# Run specific integration test (recommended) |
36 | | -./gradlew test --tests "*SearchIntegrationTest" |
| 63 | +### ⚠️ Running ALL integration tests (not recommended) |
37 | 64 |
|
38 | | -# ⚠️ Avoid running ALL integration tests at once |
39 | | -# This will perform many real operations on your workspace |
| 65 | +```bash |
| 66 | +# WARNING: Creates/modifies/deletes real data, takes 5-10+ minutes |
| 67 | +export NOTION_RUN_INTEGRATION_TESTS=true |
| 68 | +./gradlew testAll |
40 | 69 | ``` |
41 | 70 |
|
42 | | -### Environment Variables |
| 71 | +## Environment Variables |
43 | 72 |
|
44 | | -- **`NOTION_RUN_INTEGRATION_TESTS`**: Must be `"true"` to enable integration tests |
45 | | -- **`NOTION_API_TOKEN`**: Your Notion integration API token |
46 | | -- **`NOTION_TEST_PAGE_ID`**: A test page ID where the integration has permissions |
47 | | -- **`NOTION_CLEANUP_AFTER_TEST`**: Set to `"false"` to keep test data (default: cleanup enabled) |
| 73 | +| Variable | Purpose | Required For | |
| 74 | +|----------|---------|--------------| |
| 75 | +| `NOTION_RUN_INTEGRATION_TESTS` | Must be `"true"` to enable integration tests | Integration tests | |
| 76 | +| `NOTION_API_TOKEN` | Your integration secret token | Integration tests | |
| 77 | +| `NOTION_TEST_PAGE_ID` | A page where integration has permissions | Most integration tests | |
| 78 | +| `NOTION_CLEANUP_AFTER_TEST` | Set to `"false"` to keep test data | Optional (default: true) | |
48 | 79 |
|
49 | | -## Testing Your Own Code |
| 80 | +## Test Infrastructure |
| 81 | + |
| 82 | +### Official API Samples |
| 83 | + |
| 84 | +**File**: `src/test/kotlin/unit/util/TestFixtures.kt` |
| 85 | + |
| 86 | +Unit tests use real responses from Notion's API documentation: |
| 87 | + |
| 88 | +```kotlin |
| 89 | +// Load official sample responses |
| 90 | +val pageJson = TestFixtures.Pages.retrievePage() |
| 91 | +val page: Page = TestFixtures.Pages.retrievePage().decode() |
| 92 | +``` |
| 93 | + |
| 94 | +### Mock Client Builder |
| 95 | + |
| 96 | +**File**: `src/test/kotlin/unit/util/MockResponseBuilder.kt` |
50 | 97 |
|
51 | | -### Unit Testing with Mocks |
| 98 | +Create mock HTTP clients for unit tests: |
52 | 99 |
|
53 | | -_TODO: Add mocking examples showing how to test code that uses NotionClient_ |
| 100 | +```kotlin |
| 101 | +val mockClient = mockClient { |
| 102 | + addPageRetrieveResponse() // Uses official API sample |
| 103 | + addDatabaseCreateResponse() |
| 104 | +} |
| 105 | + |
| 106 | +val notion = NotionClient.createWithClient(mockClient, NotionConfig(apiToken = "test")) |
| 107 | +``` |
| 108 | + |
| 109 | +Available mock responses: `addPageRetrieveResponse()`, `addPageCreateResponse()`, `addDatabaseRetrieveResponse()`, `addBlockRetrieveResponse()`, `addSearchResponse()`, and more - see `MockResponseBuilder.kt` for complete list. |
| 110 | + |
| 111 | +## Testing Your Own Code |
| 112 | + |
| 113 | +### With mock responses (unit test) |
54 | 114 |
|
55 | 115 | ```kotlin |
56 | | -// Example using mock client (to be added) |
57 | | -class MyNotionServiceTest : FunSpec({ |
58 | | - test("should create task page") { |
59 | | - // TODO: Add complete example |
| 116 | +import io.kotest.core.spec.style.FunSpec |
| 117 | +import unit.util.mockClient |
| 118 | + |
| 119 | +class MyServiceTest : FunSpec({ |
| 120 | + test("should create page") { |
| 121 | + val mockClient = mockClient { |
| 122 | + addPageCreateResponse() |
| 123 | + } |
| 124 | + |
| 125 | + val notion = NotionClient.createWithClient(mockClient, NotionConfig(apiToken = "test")) |
| 126 | + val service = MyService(notion) |
| 127 | + |
| 128 | + val page = service.createTaskPage("Buy groceries") |
| 129 | + page.id shouldNotBe null |
60 | 130 | } |
61 | 131 | }) |
62 | 132 | ``` |
63 | 133 |
|
64 | | -### Integration Testing Pattern |
65 | | - |
66 | | -You can use the same pattern this library uses: |
| 134 | +### With real API (integration test) |
67 | 135 |
|
68 | 136 | ```kotlin |
| 137 | +import io.kotest.core.annotation.Tags |
69 | 138 | import io.kotest.core.spec.style.StringSpec |
70 | 139 | import integration.integrationTestEnvVarsAreSet |
| 140 | +import integration.shouldCleanupAfterTest |
| 141 | + |
| 142 | +@Tags("Integration", "RequiresApi") |
| 143 | +class MyServiceIntegrationTest : StringSpec({ |
71 | 144 |
|
72 | | -class MyIntegrationTest : StringSpec({ |
73 | 145 | if (!integrationTestEnvVarsAreSet()) { |
74 | | - "!(Skipped) My integration test" { |
75 | | - println("⏭️ Skipping - set NOTION_RUN_INTEGRATION_TESTS=true") |
| 146 | + "!(Skipped)" { |
| 147 | + println("⏭️ Set NOTION_RUN_INTEGRATION_TESTS=true to run") |
76 | 148 | } |
77 | 149 | } else { |
78 | | - val client = NotionClient.create(System.getenv("NOTION_API_TOKEN")) |
| 150 | + val notion = NotionClient.create(System.getenv("NOTION_API_TOKEN")) |
| 151 | + |
| 152 | + "should create and retrieve task" { |
| 153 | + val task = MyService(notion).createTask("Test task") |
| 154 | + |
| 155 | + task shouldNotBe null |
| 156 | + |
| 157 | + if (shouldCleanupAfterTest()) { |
| 158 | + notion.pages.archive(task.id) |
| 159 | + } |
| 160 | + } |
79 | 161 |
|
80 | | - "my test case" { |
81 | | - // Your test code here |
| 162 | + afterSpec { |
| 163 | + notion.close() |
82 | 164 | } |
83 | 165 | } |
84 | 166 | }) |
85 | 167 | ``` |
86 | 168 |
|
87 | | -### Test Data Management |
| 169 | +## Important Warnings |
88 | 170 |
|
89 | | -_TODO: Add guidance on managing test data in Notion workspace_ |
| 171 | +### ❌ DON'T run all integration tests at once |
90 | 172 |
|
91 | | -## Common Patterns |
| 173 | +Integration tests create/modify/delete real content in your workspace. Run them individually during development. |
92 | 174 |
|
93 | | -_TODO: Add tips, gotchas, best practices_ |
| 175 | +### ❌ DON'T test against production workspaces |
94 | 176 |
|
95 | | -### Testing Pagination |
| 177 | +Always use a dedicated test workspace or test page. Set `NOTION_TEST_PAGE_ID` to a page specifically for testing. |
96 | 178 |
|
97 | | -_TODO: Add pagination testing examples_ |
| 179 | +### ❌ DON'T commit secrets |
98 | 180 |
|
99 | | -### Testing Error Scenarios |
| 181 | +Never hardcode API tokens in test files. Always use environment variables. |
100 | 182 |
|
101 | | -_TODO: Add error scenario testing examples_ |
| 183 | +## Tag System |
| 184 | + |
| 185 | +Tests are organized with Kotest tags: |
| 186 | + |
| 187 | +| Tag | Meaning | |
| 188 | +|-----|---------| |
| 189 | +| `Unit` | Fast mock-based tests | |
| 190 | +| `Integration` + `RequiresApi` | Tests that use real Notion API | |
| 191 | +| `Slow` | Tests that take >30 seconds (also tagged Integration) | |
| 192 | +| `Examples` | Documentation example tests | |
| 193 | + |
| 194 | +Run tests by tag: |
| 195 | +```bash |
| 196 | +# Only unit tests |
| 197 | +./gradlew test -Dkotest.tags.include="Unit" |
| 198 | + |
| 199 | +# Exclude slow tests |
| 200 | +./gradlew test -Dkotest.tags.exclude="Slow" |
| 201 | +``` |
102 | 202 |
|
103 | 203 | ## Related Topics |
104 | 204 |
|
105 | | -- [Error Handling](error-handling.md) - Understanding errors to test for |
| 205 | +- **[Error Handling](error-handling.md)** - Testing error scenarios |
| 206 | +- **[CLAUDE.md](/CLAUDE.md)** - Development workflow and test commands |
0 commit comments