```python
import unittest
import json
from app import app, db, User # Assuming app and db are imported, and User model exists
# Ensure your app.py looks something like this (simplified):
# from flask import Flask, request, jsonify
# from flask_sqlalchemy import SQLAlchemy
#
# app = Flask(__name__)
# app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///test.db' # Use an in-memory or test database
# app.config['TESTING'] = True
# app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
# db = SQLAlchemy(app)
#
# class User(db.Model):
# id = db.Column(db.Integer, primary_key=True)
# username = db.Column(db.String(80), unique=True, nullable=False)
# email = db.Column(db.String(120), unique=True, nullable=False)
#
# def __repr__(self):
# return f'<User {self.username}>'
#
# def to_dict(self):
# return {"id": self.id, "username": self.username, "email": self.email}
#
# @app.route('/api/v1/users', methods=['POST'])
# def create_user():
# data = request.get_json()
# if not data or not all(k in data for k in ['username', 'email']):
# return jsonify({"message": "Missing username or email"}), 400
#
# username = data['username']
# email = data['email']
#
# if User.query.filter_by(email=email).first():
# return jsonify({"message": "Email already registered"}), 400
# if User.query.filter_by(username=username).first():
# return jsonify({"message": "Username already taken"}), 400
#
# new_user = User(username=username, email=email)
# db.session.add(new_user)
# db.session.commit()
#
# return jsonify(new_user.to_dict()), 201
#
# with app.app_context():
# db.create_all()
class TestUserCreationEndpoint(unittest.TestCase):
def setUp(self):
# Set up a test client and a clean database for each test
self.app = app.test_client()
self.app_context = app.app_context()
self.app_context.push()
db.create_all() # Ensure tables are created for testing
# Clear any existing data before each test
User.query.delete()
db.session.commit()
def tearDown(self):
# Clean up database after each test
db.session.remove()
db.drop_all()
self.app_context.pop()
def test_create_user_success(self):
"""Test creating a new user successfully."""
data = {'username': 'testuser', 'email': 'test@example.com'}
response = self.app.post(
'/api/v1/users',
data=json.dumps(data),
content_type='application/json'
)
self.assertEqual(response.status_code, 201)
response_data = json.loads(response.data)
self.assertIn('id', response_data)
self.assertEqual(response_data['username'], 'testuser')
self.assertEqual(response_data['email'], 'test@example.com')
self.assertIsNotNone(User.query.filter_by(username='testuser').first())
def test_create_user_missing_username(self):
"""Test creating a user with missing username field."""
data = {'email': 'missing_user@example.com'}
response = self.app.post(
'/api/v1/users',
data=json.dumps(data),
content_type='application/json'
)
self.assertEqual(response.status_code, 400)
response_data = json.loads(response.data)
self.assertIn("Missing username or email", response_data['message'])
def test_create_user_missing_email(self):
"""Test creating a user with missing email field."""
data = {'username': 'missing_email'}
response = self.app.post(
'/api/v1/users',
data=json.dumps(data),
content_type='application/json'
)
self.assertEqual(response.status_code, 400)
response_data = json.loads(response.data)
self.assertIn("Missing username or email", response_data['message'])
def test_create_user_duplicate_email(self):
"""Test creating a user with an email that already exists."""
# First, create a user successfully
initial_data = {'username': 'firstuser', 'email': 'duplicate@example.com'}
self.app.post('/api/v1/users', data=json.dumps(initial_data), content_type='application/json')
# Try to create another user with the same email
duplicate_data = {'username': 'seconduser', 'email': 'duplicate@example.com'}
response = self.app.post(
'/api/v1/users',
data=json.dumps(duplicate_data),
content_type='application/json'
)
self.assertEqual(response.status_code, 400)
response_data = json.loads(response.data)
self.assertIn("Email already registered", response_data['message'])
def test_create_user_duplicate_username(self):
"""Test creating a user with a username that already exists."""
# First, create a user successfully
initial_data = {'username': 'duplicate_name', 'email': 'unique1@example.com'}
self.app.post('/api/v1/users', data=json.dumps(initial_data), content_type='application/json')
# Try to create another user with the same username
duplicate_data = {'username': 'duplicate_name', 'email': 'unique2@example.com'}
response = self.app.post(
'/api/v1/users',
data=json.dumps(duplicate_data),
content_type='application/json'
)
self.assertEqual(response.status_code, 400)
response_data = json.loads(response.data)
self.assertIn("Username already taken", response_data['message'])
def test_create_user_empty_json(self):
"""Test creating a user with an empty JSON body."""
response = self.app.post(
'/api/v1/users',
data=json.dumps({}),
content_type='application/json'
)
self.assertEqual(response.status_code, 400)
response_data = json.loads(response.data)
self.assertIn("Missing username or email", response_data['message'])
def test_create_user_no_json_header(self):
"""Test creating a user without the application/json content type header."""
data = {'username': 'noheader', 'email': 'noheader@example.com'}
response = self.app.post(
'/api/v1/users',
data=json.dumps(data) # No content_type specified
)
# Flask's default behavior for missing content-type with json.dumps can be 400
# or 415 depending on how it's handled. Check your app's actual behavior.
# For simplicity, if your app explicitly checks for request.is_json, this will fail.
# Assuming the endpoint expects application/json explicitly.
self.assertEqual(response.status_code, 400)
response_data = json.loads(response.data)
self.assertIn("Missing username or email", response_data['message']) # Or similar message from request.get_json() failing
if __name__ == '__main__':
unittest.main()
```