/tdd_challenge

Created to demonstate tdd to learners

Primary LanguagePython

TDD Simplified

CircleCI Coverage Status Codacy Badge

The Test Driven Development Cycle

flowchart LR
A[Write a Test]-->B[Fail Test]-->C[Write Code]-->D[Pass Test]-->E[Refactor]-->A

User Model

Complete User Model

A representation of the complete User model that we will have after refactoring the code

classDiagram
 class User
 User : +id Integer
 User : +name String
 User : +username String
 User : -password String
 User : +insert()
 User : +update()
 User : +delete()
 User : serialize
 User : __repr__()
 

A Simple User model

We are going to start with a simple User Model so that we can fully grasp and appreciate the TDD workflow

classDiagram
 class User
 User: +id Integer
 User : +username String
 User : +insert()
 User : +update()
 User : +delete()
 User : serialize
 User : __repr__()

End Points Sequence Diagrams

Get Users: GET /users

graph LR
A[GET Users] -->B[(Are there users in the Database?)]
B -->|No|C[Return 200 OK and Empty list]
B -->|Yes|D[Return 200 OK and list of Users]

Get a User: GET /users/<user_id>

graph LR
A[GET User] -->B{Is user id valid?}
B -->|No|C[Return 404 Not Found and Error message]
B -->|Yes|D[Return 200 OK and User object for specified id]

Create a User: POST /users

graph TD
A[Post User]-->B
B[Get User Data]-->C{Is Data Valid}
C -->|No|D[Return 400 Bad Request and Message]
C -->|Yes|E{Does User Already Exist }
E -->|Yes|F[Return 409 Conflict and Message]
E -->|No|G[Create User]
G -->|No|H[(Has the User Been Created?)]
H -->|Success|I[Return 201 Created, Message, and Created User]
H -->|Failure|J[Return 500 Internal Server Error and Message]

Update a User: PUT /users

graph TD
A[PUT User] --> B{Is user id valid}
B -->|No|C[Return 404 Not Found and Error message]
B -->|Yes|D{Is Data Valid}
D -->|No|E[Return 400 Bad Request and Error Message]
D -->|Yes|F{Is Username Unique}
F -->|No|G[Return 409 Conflict and Error Message]
F -->|Yes|H[(Has the User data been updated)]
H -->|Sucess - Modified|I[Return 200 Ok and Message]
H -->|Sucess - Not modified|J[Return 204 No Content]
H -->|Failure - Error occured |K[Return 500 Internal Server Error]

Delete a User: DELETE /users/<user_id>

graph TD
A[DELETE User] --> B{Is user id valid?}
B -->|No| C[Return 404 Not Found and Error message]
B -->E[(Delete the user!)]
E -->|Failure|F[Return 500 Internal Server Error and Error Message]
E -->|success| G{Does Response Contain body?}
G-->|Yes|H[Return 200 OK and Message]
G -->|No|J[Return 204 No Content]


Dependencies

How to set up and run the project

  • Create and Activate a Python virtual environment

  • Install requirements

    pip install -r requirements.txt 
  • Set environment variables specified in the env_sample.txt

    • DATABASE_URL for Production
    • DEV_DATABASE_URL for Development
    • TEST_DATABASE_URL for Testing

      Remember to create separate databases for testing and running the code

  • Update the migrations

    flask db upgrade
  • Run the project

    python -m run

How to Create and Activate a Python virtual Environment

  • Open your terminal at the root of the project

  • create a virtual environment

    python -m venv env
  • Activate the virtual environment

    • for windows
      env\Scripts\activate
    • for linux\macOS
      source env/bin/activate
  • Deactivate the virtual environment

    deactivate

How to run tests

  • Activate the virtual environment
  • Create you test database
  • SET the TEST_DATABASE_URL environment variable
  • Run the tests using pytest
      pytest tests

Important to know

how to get json data from the request object

{
  "username": "Arthur"
}
  1. json returns a python dictionary with key-value pairs

    • The parsed JSON data if mimetypeindicates JSON (*application/json)is_json) .

    • Calls get_json()with default arguments.

    • If the request content type is not application/json, this will raise a 400 Bad Request error.

      data = request.json
      username = data["username"]
  2. get_json(force=False, silent=False, _ cache=True_) returns a dict with key-value pairs

    • Raises a 400 error if the content type is incorrect.

    • force (bool) – Ignore the mimetype and always try to parse JSON.

      data = request.get_json(force=True)
  3. flask.json.loads(s, app=None, ** kwargs)

    • Serialize an object to a string of JSON.

      data = json.loads(request.data.decode())

How to convert to python objects to JSON String

  1. flask.json.jsonify

    • Serialize data to JSON and wrap it in a Response with the application/json mimetype

      jsonify({"username": "Arthur"})
  2. flask.json.dumps(obj, app=None, ** kwargs)

    • Serialize an object to a string of JSON.

      user_dict = { "username": "Arthur" }
      json_data = json.dumps(user_dict)

References