Skip to content

Commit 5738443

Browse files
committed
update e2e tests
1 parent 0d925f7 commit 5738443

File tree

4 files changed

+139
-34
lines changed

4 files changed

+139
-34
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,5 @@
1313

1414
# Dependency directories (remove the comment below to include it)
1515
# vendor/
16+
__pycache__
17+
.pytest_cache

README.md

Lines changed: 74 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,78 @@ curl -H "Authorization: Bearer <YOUR_TOKEN>" http://localhost:8001/api/v1/books
143143

144144
Pull requests are welcome. For major changes, please open an issue first to discuss what you would like to change.
145145

146-
## TODOs
146+
## End-to-End (E2E) Tests
147147

148-
- Unit tests
148+
This project contains end-to-end (E2E) tests to verify the functionality of the API. The tests are written in Python using the `pytest` framework.
149+
150+
### Prerequisites
151+
152+
Before running the tests, ensure you have the following:
153+
154+
- Python 3.x installed
155+
- `pip` (Python package manager)
156+
- The API service running locally or on a staging server
157+
- API key available
158+
159+
### Setup
160+
161+
#### 1. Create a virtual environment (optional but recommended):
162+
163+
```bash
164+
python -m venv venv
165+
source venv/bin/activate # On Windows: venv\Scripts\activate
166+
```
167+
168+
#### 2. Install dependencies:
169+
170+
```bash
171+
pip install -r requirements.txt
172+
```
173+
174+
The main dependency is `requests`, but you may need to include it in your `requirements.txt` file if it's not already listed.
175+
176+
##@# 3. Set up the environment variables:
177+
178+
You need to set the `BASE_URL` and `API_KEY` as environment variables before running the tests.
179+
180+
For a **local** API service:
181+
182+
```bash
183+
export BASE_URL=http://localhost:8001/api/v1
184+
export API_KEY=your-api-key-here
185+
```
186+
187+
For a **staging** server:
188+
189+
```bash
190+
export BASE_URL=https://staging-server-url.com/api/v1
191+
export API_KEY=your-api-key-here
192+
```
193+
194+
On **Windows**, you can use:
195+
196+
```bash
197+
set BASE_URL=http://localhost:8001/api/v1
198+
set API_KEY=your-api-key-here
199+
```
200+
201+
#### 4. Run the tests:
202+
203+
Once the environment variables are set, you can run the tests using `pytest`:
204+
205+
```bash
206+
pytest test_e2e.py
207+
```
208+
209+
### Test Structure
210+
211+
The tests will perform the following actions:
212+
213+
1. Register a new user and obtain a JWT token.
214+
2. Create a new book in the system.
215+
3. Retrieve all books and verify the created book is present.
216+
4. Retrieve a specific book by its ID.
217+
5. Update the book's details.
218+
6. Delete the book and verify it is no longer accessible.
219+
220+
Each test includes assertions to ensure that the API behaves as expected.

pkg/api/user.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ func (r *userRepository) LoginHandler(c *gin.Context) {
9494
// @Accept json
9595
// @Produce json
9696
// @Param user body models.LoginUser true "User registration object"
97-
// @Success 200 {string} string "Successfully registered"
97+
// @Success 201 {string} string "Successfully registered"
9898
// @Failure 400 {string} string "Bad Request"
9999
// @Failure 500 {string} string "Internal Server Error"
100100
// @Router /register [post]
@@ -122,5 +122,5 @@ func (r *userRepository) RegisterHandler(c *gin.Context) {
122122
return
123123
}
124124

125-
c.JSON(http.StatusOK, gin.H{"message": "Registration successful"})
125+
c.JSON(http.StatusCreated, gin.H{"message": "Registration successful"})
126126
}

tests/e2e.py

Lines changed: 61 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import requests
22
import json
3+
import pytest
34

45
# Define the base URL
56
BASE_URL = "http://localhost:8001/api/v1"
@@ -11,72 +12,102 @@
1112
def get_jwt_token():
1213
# User registration (assuming it doesn't need authentication)
1314
register_url = f"{BASE_URL}/register"
14-
register_data = json.dumps({"username": "testuser", "password": "securepassword"})
15+
register_data = json.dumps({"username": "user1", "password": "securepassword"})
1516
register_response = requests.post(register_url, headers=headers, data=register_data)
16-
print("Register User:", register_response.status_code, register_response.json())
17+
18+
assert register_response.status_code in [200, 201], f"User registration failed: {register_response.status_code}"
1719

1820
# User login
1921
login_url = f"{BASE_URL}/login"
20-
login_data = json.dumps({"username": "testuser", "password": "securepassword"})
22+
login_data = json.dumps({"username": "user1", "password": "securepassword"})
2123
login_response = requests.post(login_url, headers=headers, data=login_data)
22-
print("Login User:", login_response.status_code, login_response.json())
24+
25+
assert login_response.status_code == 200, f"User login failed: {login_response.status_code}"
2326

2427
# Extracting JWT token from login response
25-
jwt_token = login_response.json().get('token')
28+
jwt_token = login_response.json().get('token')
29+
assert jwt_token is not None, "JWT token not found in login response"
30+
2631
return jwt_token
2732

2833
# Create a new book
29-
def test_create_book(jwt_token):
34+
def create_book(jwt_token):
3035
url = f"{BASE_URL}/books"
3136
auth_headers = {**headers, "Authorization": f"Bearer {jwt_token}"}
3237
data = json.dumps({"author": "Jane Doe", "title": "New Book Title"})
3338
response = requests.post(url, headers=auth_headers, data=data)
34-
print("Create Book:", response.status_code, response.json())
39+
40+
assert response.status_code == 201, f"Failed to create book: {response.status_code}"
3541
return response.json()
3642

3743
# Get all books
38-
def test_get_books(jwt_token):
44+
def get_books(jwt_token):
3945
url = f"{BASE_URL}/books"
4046
auth_headers = {**headers, "Authorization": f"Bearer {jwt_token}"}
4147
response = requests.get(url, headers=auth_headers)
42-
print("Get Books:", response.status_code, response.json())
48+
49+
assert response.status_code == 200, f"Failed to get books: {response.status_code}"
50+
return response.json()
4351

4452
# Get a specific book by ID
45-
def test_get_book(book_id, jwt_token):
53+
def get_book(book_id, jwt_token):
4654
url = f"{BASE_URL}/books/{book_id}"
4755
auth_headers = {**headers, "Authorization": f"Bearer {jwt_token}"}
4856
response = requests.get(url, headers=auth_headers)
49-
print("Get Book:", response.status_code, response.json())
57+
58+
assert response.status_code == 200, f"Failed to get book: {response.status_code}"
59+
return response.json()
5060

5161
# Update a book
52-
def test_update_book(book_id, jwt_token):
62+
def update_book(book_id, jwt_token):
5363
url = f"{BASE_URL}/books/{book_id}"
5464
auth_headers = {**headers, "Authorization": f"Bearer {jwt_token}"}
5565
data = json.dumps({"author": "John Smith", "title": "Updated Book Title"})
5666
response = requests.put(url, headers=auth_headers, data=data)
57-
print("Update Book:", response.status_code, response.json())
67+
68+
assert response.status_code == 200, f"Failed to update book: {response.status_code}"
69+
return response.json()
5870

5971
# Delete a book
60-
def test_delete_book(book_id, jwt_token):
72+
def delete_book(book_id, jwt_token):
6173
url = f"{BASE_URL}/books/{book_id}"
6274
auth_headers = {**headers, "Authorization": f"Bearer {jwt_token}"}
6375
response = requests.delete(url, headers=auth_headers)
64-
print("Delete Book:", response.status_code)
76+
77+
assert response.status_code == 204, f"Failed to delete book: {response.status_code}"
78+
79+
# Tests using pytest
80+
@pytest.fixture(scope="module")
81+
def jwt_token():
82+
return get_jwt_token()
83+
84+
def test_create_book(jwt_token):
85+
book = create_book(jwt_token)
86+
assert book['data']['author'] == "Jane Doe"
87+
assert book['data']['title'] == "New Book Title"
88+
return book
89+
90+
def test_get_books(jwt_token):
91+
books = get_books(jwt_token)
92+
assert isinstance(books, dict), "Books response is not a dictionary"
93+
assert 'data' in books, "Books data not found in response"
6594

66-
# Run tests
67-
def run_tests():
68-
# Authenticate and obtain JWT
69-
jwt_token = get_jwt_token()
70-
if jwt_token:
71-
# Create a book and use its ID for further tests
72-
book = test_create_book(jwt_token)
73-
book_id = book['data']['id']
95+
def test_get_book(jwt_token):
96+
book = create_book(jwt_token)
97+
book_id = book['data']['id']
98+
fetched_book = get_book(book_id, jwt_token)
99+
assert fetched_book['data']['id'] == book_id, "Fetched book ID does not match created book ID"
74100

75-
# Perform operations
76-
test_get_books(jwt_token)
77-
test_get_book(book_id, jwt_token)
78-
test_update_book(book_id, jwt_token)
79-
test_delete_book(book_id, jwt_token)
101+
def test_update_book(jwt_token):
102+
book = create_book(jwt_token)
103+
book_id = book['data']['id']
104+
updated_book = update_book(book_id, jwt_token)
105+
assert updated_book['data']['author'] == "John Smith", "Book author not updated"
106+
assert updated_book['data']['title'] == "Updated Book Title", "Book title not updated"
80107

81-
if __name__ == "__main__":
82-
run_tests()
108+
def test_delete_book(jwt_token):
109+
book = create_book(jwt_token)
110+
book_id = book['data']['id']
111+
delete_book(book_id, jwt_token)
112+
with pytest.raises(AssertionError):
113+
get_book(book_id, jwt_token) # This should raise an error since the book is deleted

0 commit comments

Comments
 (0)