-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
9f35142
commit 03b1dda
Showing
1 changed file
with
262 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,262 @@ | ||
# **Testing RESTful APIs** | ||
|
||
Testing is an essential part of API development. It ensures that the endpoints behave as expected and helps catch bugs early in the development process. In this section, we’ll cover automated testing using **`pytest`** for **Flask** and **`unittest`** or **`pytest-django`** for **Django**. We’ll also provide a mini-tutorial on how to manually test APIs using **Postman**. | ||
|
||
## **1. Automated Testing in Flask with pytest** | ||
|
||
Testing APIs in Flask is straightforward using **`pytest`**. We’ll start by setting up basic test cases for CRUD operations, and then move on to testing authenticated routes. | ||
|
||
### **Step 1: Install pytest** | ||
```bash | ||
pipenv install pytest pytest-flask | ||
``` | ||
|
||
### **Step 2: Setting Up Test Configuration** | ||
In **`tests/conftest.py`**, create a test configuration to set up a test environment for your Flask app. | ||
|
||
```python | ||
import pytest | ||
from app import create_app, db | ||
|
||
@pytest.fixture | ||
def app(): | ||
app = create_app() | ||
app.config.update({ | ||
"TESTING": True, | ||
"SQLALCHEMY_DATABASE_URI": "sqlite:///:memory:", # Use in-memory database for testing | ||
}) | ||
|
||
with app.app_context(): | ||
db.create_all() # Create the database for tests | ||
yield app # Provide the app to the tests | ||
db.session.remove() | ||
db.drop_all() | ||
|
||
@pytest.fixture | ||
def client(app): | ||
return app.test_client() # Provide a test client | ||
``` | ||
- **`TESTING`**: Enables testing mode in Flask. | ||
- **`SQLALCHEMY_DATABASE_URI`**: Uses an in-memory SQLite database for testing purposes. | ||
- **`client`**: Provides a test client for making requests to the Flask application. | ||
|
||
### **Step 3: Writing Test Cases** | ||
Now, let’s write test cases for CRUD operations and authentication. In **`tests/test_api.py`**, we create tests using pytest. | ||
|
||
```python | ||
def test_create_user(client): | ||
response = client.post('/users', json={ | ||
"name": "John Doe", | ||
"email": "[email protected]", | ||
"age": 30 | ||
}) | ||
assert response.status_code == 201 | ||
data = response.get_json() | ||
assert data['name'] == "John Doe" | ||
|
||
def test_get_users(client): | ||
response = client.get('/users') | ||
assert response.status_code == 200 | ||
data = response.get_json() | ||
assert len(data) > 0 # Ensure we get a list of users | ||
|
||
def test_get_single_user(client): | ||
response = client.get('/users/1') | ||
assert response.status_code == 200 | ||
data = response.get_json() | ||
assert data['id'] == 1 | ||
|
||
def test_update_user(client): | ||
response = client.put('/users/1', json={"name": "Jane Doe"}) | ||
assert response.status_code == 200 | ||
data = response.get_json() | ||
assert data['name'] == "Jane Doe" | ||
|
||
def test_delete_user(client): | ||
response = client.delete('/users/1') | ||
assert response.status_code == 200 | ||
``` | ||
- **Test Case Breakdown**: | ||
- **`test_create_user`**: Tests the creation of a new user via the POST method. | ||
- **`test_get_users`**: Tests retrieving a list of users via the GET method. | ||
- **`test_get_single_user`**: Tests retrieving a specific user by ID. | ||
- **`test_update_user`**: Tests updating a user’s information. | ||
- **`test_delete_user`**: Tests deleting a user. | ||
|
||
### **Step 4: Running the Tests** | ||
To run the tests, simply execute: | ||
```bash | ||
pytest | ||
``` | ||
This will discover and execute all tests within the **`tests/`** directory. | ||
|
||
--- | ||
|
||
## **2. Automated Testing in Django with pytest-django** | ||
|
||
For Django, we can use either the built-in **`unittest`** module or **`pytest-django`** for testing. We’ll cover both approaches, but we recommend using **`pytest-django`** for better flexibility and features. | ||
|
||
### **Option 1: Using pytest-django** | ||
|
||
### **Step 1: Install pytest-django** | ||
```bash | ||
pipenv install pytest pytest-django | ||
``` | ||
|
||
### **Step 2: Configure pytest-django** | ||
In your **`pytest.ini`** or **`conftest.py`** file, configure the test environment: | ||
|
||
```ini | ||
[pytest] | ||
DJANGO_SETTINGS_MODULE = django_crud_api.settings | ||
``` | ||
|
||
### **Step 3: Writing Test Cases** | ||
Create a test file in **`users/tests/test_views.py`**: | ||
|
||
```python | ||
import pytest | ||
from django.urls import reverse | ||
from rest_framework.test import APIClient | ||
from users.models import User | ||
|
||
@pytest.fixture | ||
def api_client(): | ||
return APIClient() | ||
|
||
@pytest.fixture | ||
def create_user(): | ||
return User.objects.create(name="John Doe", email="[email protected]", age=30) | ||
|
||
def test_create_user(api_client): | ||
url = reverse('user-list') # Use Django’s reverse function for the URL | ||
response = api_client.post(url, {"name": "Jane Doe", "email": "[email protected]", "age": 25}, format='json') | ||
assert response.status_code == 201 | ||
assert response.data['name'] == "Jane Doe" | ||
|
||
def test_get_users(api_client, create_user): | ||
url = reverse('user-list') | ||
response = api_client.get(url) | ||
assert response.status_code == 200 | ||
assert len(response.data) > 0 | ||
|
||
def test_update_user(api_client, create_user): | ||
url = reverse('user-detail', args=[create_user.id]) | ||
response = api_client.put(url, {"name": "John Smith", "email": "[email protected]"}, format='json') | ||
assert response.status_code == 200 | ||
assert response.data['name'] == "John Smith" | ||
|
||
def test_delete_user(api_client, create_user): | ||
url = reverse('user-detail', args=[create_user.id]) | ||
response = api_client.delete(url) | ||
assert response.status_code == 204 | ||
``` | ||
- **`reverse()`**: Generates the URL for API endpoints. | ||
- **APIClient**: DRF’s test client for making API requests. | ||
|
||
### **Step 4: Running Tests** | ||
To run the tests: | ||
```bash | ||
pytest | ||
``` | ||
|
||
--- | ||
|
||
### **Option 2: Using Django's Unittest Framework** | ||
|
||
If you prefer **`unittest`**, you can write test cases similarly. In **`users/tests.py`**, add: | ||
|
||
```python | ||
from django.test import TestCase | ||
from django.urls import reverse | ||
from users.models import User | ||
|
||
class UserTests(TestCase): | ||
def setUp(self): | ||
self.user = User.objects.create(name="John Doe", email="[email protected]", age=30) | ||
|
||
def test_create_user(self): | ||
response = self.client.post(reverse('user-list'), { | ||
"name": "Jane Doe", "email": "[email protected]", "age": 25 | ||
}) | ||
self.assertEqual(response.status_code, 201) | ||
self.assertEqual(response.data['name'], "Jane Doe") | ||
|
||
def test_get_users(self): | ||
response = self.client.get(reverse('user-list')) | ||
self.assertEqual(response.status_code, 200) | ||
self.assertGreater(len(response.data), 0) | ||
|
||
def test_update_user(self): | ||
response = self.client.put(reverse('user-detail', args=[self.user.id]), { | ||
"name": "John Smith", "email": "[email protected]" | ||
}) | ||
self.assertEqual(response.status_code, 200) | ||
self.assertEqual(response.data['name'], "John Smith") | ||
|
||
def test_delete_user(self): | ||
response = self.client.delete(reverse('user-detail', args=[self.user.id])) | ||
self.assertEqual(response.status_code, 204) | ||
``` | ||
|
||
Run these tests with: | ||
```bash | ||
python manage.py test | ||
``` | ||
|
||
--- | ||
|
||
## **3. Manual Testing Using Postman** | ||
|
||
**Postman** is a powerful tool that allows you to manually test your RESTful APIs by sending HTTP requests to your server. | ||
|
||
### **Step 1: Setting Up Postman** | ||
|
||
1. **Install Postman**: Download and install Postman from the [official website](https://www.postman.com/downloads/). | ||
2. **Create a New Collection**: Organize your API requests in a collection. A collection helps you manage different endpoints, including GET, POST, PUT, and DELETE requests. | ||
|
||
### **Step 2: Sending Requests** | ||
|
||
Here’s a mini-tutorial to test each CRUD operation manually: | ||
|
||
1. **POST (Create a User)**: | ||
- In Postman, select **POST** and enter the URL: `http://127.0.0.1:5000/users` (or your Django API URL). | ||
- In the **Body** tab, select **raw** and **JSON** format, then enter the following JSON: | ||
```json | ||
{ | ||
"name": "Jane Doe", | ||
"email": "[email protected]", | ||
"age": 25 | ||
} | ||
``` | ||
- Click **Send** to create the user. You should receive a **201 Created** response with the new user’s details. | ||
|
||
2. **GET (Retrieve All Users)**: | ||
- Select **GET** and enter `http://127.0.0.1:5000/users`. | ||
- Click **Send**. You should receive a **200 OK** response with a list of users. | ||
|
||
3. **GET (Retrieve a Single User)**: | ||
- Select **GET** and enter `http://127.0.0.1:5000/users/1` (replace `1` with the correct user ID). | ||
- Click **Send**. You | ||
|
||
should receive a **200 OK** response with the user’s details. | ||
|
||
4. **PUT (Update a User)**: | ||
- Select **PUT** and enter `http://127.0.0.1:5000/users/1`. | ||
- In the **Body** tab, enter the updated user details: | ||
```json | ||
{ | ||
"name": "Jane Smith", | ||
"email": "[email protected]" | ||
} | ||
``` | ||
- Click **Send** to update the user. You should receive a **200 OK** response with the updated details. | ||
|
||
5. **DELETE (Delete a User)**: | ||
- Select **DELETE** and enter `http://127.0.0.1:5000/users/1`. | ||
- Click **Send**. You should receive a **200 OK** response with a confirmation of the deletion. | ||
|
||
## **4. Conclusion** | ||
|
||
- Testing RESTful APIs is critical for ensuring their correctness and reliability. With automated testing in Flask and Django using **`pytest`**, **`unittest`**, or **`pytest-django`**, you can cover a wide range of test cases for your endpoints. Postman provides a manual way to test your APIs and verify responses. | ||
|