Skip to content

Commit 85574e6

Browse files
committed
test: add integration tests against real MongoDB
- tests/test_integration.py: per-repo pytest tests that connect to a real MongoDB instance and exercise the actual collection schema with CRUD operations - tests/__init__.py: makes tests a package so pytest resolves modules correctly - .github/workflows/ci.yml: adds mongo:latest service container (health-checked, port 27017) and a step that runs pytest tests/test_integration.py with MONGODB_URI pointing at the service container credentials Pattern follows mongodb-developer/mern-stack-example PR #51.
1 parent 04571ad commit 85574e6

3 files changed

Lines changed: 142 additions & 0 deletions

File tree

.github/workflows/ci.yml

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,20 @@ jobs:
99
smoke:
1010
runs-on: ubuntu-latest
1111

12+
services:
13+
mongodb:
14+
image: mongo:latest
15+
options: >-
16+
--health-cmd mongosh
17+
--health-interval 10s
18+
--health-timeout 5s
19+
--health-retries 5
20+
ports:
21+
- 27017:27017
22+
env:
23+
MONGO_INITDB_ROOT_USERNAME: admin
24+
MONGO_INITDB_ROOT_PASSWORD: mongodb
25+
1226
steps:
1327
- name: Checkout
1428
uses: actions/checkout@v4
@@ -98,3 +112,11 @@ jobs:
98112
echo "No runtime smoke test file found"
99113
exit 1
100114
fi
115+
116+
- name: Install integration test dependencies
117+
run: pip install pytest pymongo
118+
119+
- name: Run integration tests
120+
env:
121+
MONGODB_URI: mongodb://admin:mongodb@localhost:27017/
122+
run: pytest tests/test_integration.py -v

tests/__init__.py

Whitespace-only changes.

tests/test_integration.py

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
"""Integration tests for FARM-Intro.
2+
3+
Tests real MongoDB CRUD operations for the task data model
4+
used by the FARM-Intro backend.
5+
6+
Requires a running MongoDB instance. Set MONGODB_URI (default:
7+
mongodb://admin:mongodb@localhost:27017/) or the tests will be skipped.
8+
"""
9+
10+
import os
11+
import pytest
12+
from pymongo import MongoClient
13+
from bson import ObjectId
14+
15+
MONGODB_URI = os.environ.get("MONGODB_URI", "mongodb://admin:mongodb@localhost:27017/")
16+
TEST_DB = "farm_intro_integration_test"
17+
18+
19+
@pytest.fixture(scope="module")
20+
def db():
21+
client = MongoClient(MONGODB_URI, serverSelectionTimeoutMS=2000)
22+
try:
23+
client.admin.command("ping")
24+
except Exception:
25+
client.close()
26+
pytest.skip(f"MongoDB not reachable at {MONGODB_URI}")
27+
database = client[TEST_DB]
28+
yield database
29+
client.drop_database(TEST_DB)
30+
client.close()
31+
32+
33+
def test_mongodb_ping():
34+
client = MongoClient(MONGODB_URI, serverSelectionTimeoutMS=2000)
35+
try:
36+
result = client.admin.command("ping")
37+
assert result.get("ok") == 1.0
38+
except Exception:
39+
pytest.skip(f"MongoDB not reachable at {MONGODB_URI}")
40+
finally:
41+
client.close()
42+
43+
44+
def test_task_create_and_find(db):
45+
"""Tasks collection: insert and retrieve a task."""
46+
tasks = db["tasks"]
47+
48+
task_id = str(ObjectId())
49+
task = {
50+
"_id": task_id,
51+
"title": "Learn FastAPI",
52+
"description": "Build a FARM stack app",
53+
"completed": False,
54+
}
55+
56+
result = tasks.insert_one(task)
57+
assert result.inserted_id == task_id
58+
59+
found = tasks.find_one({"_id": task_id})
60+
assert found["title"] == "Learn FastAPI"
61+
assert found["completed"] is False
62+
63+
# Cleanup
64+
tasks.delete_one({"_id": task_id})
65+
66+
67+
def test_task_update(db):
68+
"""Tasks collection: update a task's completion status."""
69+
tasks = db["tasks"]
70+
71+
task_id = str(ObjectId())
72+
tasks.insert_one({"_id": task_id, "title": "Write tests", "completed": False})
73+
74+
tasks.update_one({"_id": task_id}, {"$set": {"completed": True}})
75+
updated = tasks.find_one({"_id": task_id})
76+
assert updated["completed"] is True
77+
78+
# Cleanup
79+
tasks.delete_one({"_id": task_id})
80+
81+
82+
def test_task_list(db):
83+
"""Tasks collection: list all tasks returns correct count."""
84+
tasks = db["tasks"]
85+
86+
ids = [str(ObjectId()) for _ in range(3)]
87+
docs = [
88+
{"_id": ids[0], "title": "Task 1", "completed": False},
89+
{"_id": ids[1], "title": "Task 2", "completed": True},
90+
{"_id": ids[2], "title": "Task 3", "completed": False},
91+
]
92+
tasks.insert_many(docs)
93+
94+
all_tasks = list(tasks.find({}))
95+
assert len(all_tasks) >= 3
96+
97+
incomplete = list(tasks.find({"completed": False}))
98+
assert all(not t["completed"] for t in incomplete)
99+
100+
# Cleanup
101+
tasks.delete_many({"_id": {"$in": ids}})
102+
103+
104+
def test_task_delete(db):
105+
"""Tasks collection: delete a task and confirm it is gone."""
106+
tasks = db["tasks"]
107+
108+
task_id = str(ObjectId())
109+
tasks.insert_one({"_id": task_id, "title": "To be deleted", "completed": False})
110+
111+
delete_result = tasks.delete_one({"_id": task_id})
112+
assert delete_result.deleted_count == 1
113+
114+
assert tasks.find_one({"_id": task_id}) is None
115+
116+
117+
def test_task_not_found(db):
118+
"""Tasks collection: querying a non-existent task returns None."""
119+
tasks = db["tasks"]
120+
assert tasks.find_one({"_id": "nonexistent-id"}) is None

0 commit comments

Comments
 (0)