Skip to content

Commit

Permalink
Merge pull request #6 from devzero-inc/feature/unit-test-05
Browse files Browse the repository at this point in the history
#5 AS: refactored backend code, written unit tests for the app
  • Loading branch information
AdoshSingh authored Mar 22, 2024
2 parents 1443b08 + 93a6e9b commit 30c675a
Show file tree
Hide file tree
Showing 12 changed files with 5,005 additions and 1,805 deletions.
81 changes: 6 additions & 75 deletions backend/app.py
Original file line number Diff line number Diff line change
@@ -1,83 +1,14 @@
from flask import Flask, jsonify, request
import mysql.connector
from mysql.connector import Error
import os
from flask import Flask
from flask_cors import CORS
from dotenv import load_dotenv
from flask_cors import CORS

app = Flask(__name__)
CORS(app)
import routes

load_dotenv()

DATABASE_CONFIG = {
'host': os.getenv('DB_HOST'),
'database': os.getenv('DB_DATABASE'),
'user': os.getenv('DB_USER'),
'password': os.getenv('DB_PASSWORD')
}

def get_db_connection():
try:
conn = mysql.connector.connect(**DATABASE_CONFIG)
if conn.is_connected():
return conn
except Error as e:
print(f"Error connecting to MySQL Database: {e}")
return None

@app.route('/accounts', methods=['GET'])
def get_accounts():
conn = get_db_connection()
if conn:
cursor = conn.cursor(dictionary=True)
cursor.execute('SELECT * FROM accounts')
accounts = cursor.fetchall()
cursor.close()
conn.close()
return jsonify({"data": accounts})
else:
return jsonify({"error": "Database connection failed"}), 500
app = Flask(__name__)
CORS(app)

@app.route('/transactions', methods=['GET'])
def get_transactions():
conn = get_db_connection()
if conn:
cursor = conn.cursor(dictionary=True)
cursor.execute('SELECT * FROM transactions')
transactions = cursor.fetchall()
cursor.close()
conn.close()
return jsonify({"data": transactions})
else:
return jsonify({"error": "Database connection failed"}), 500

@app.route('/transactions', methods=['POST'])
def add_transaction():
transaction_data = request.json
conn = get_db_connection()
if conn:
cursor = conn.cursor()
cursor.execute(
'INSERT INTO transactions '
'(account_id, bank_name, date, type, payee, amount, category) '
'VALUES (%s, %s, %s, %s, %s, %s, %s)',
(
transaction_data['account_id'],
transaction_data['bank_name'],
transaction_data['date'],
transaction_data['type'],
transaction_data['payee'],
transaction_data['amount'],
transaction_data['category']
)
)
conn.commit()
cursor.close()
conn.close()
return jsonify({"message": "Transaction added successfully"}), 201
else:
return jsonify({"error": "Database connection failed"}), 500
app.register_blueprint(routes.api)

if __name__ == "__main__":
app.run(debug=True)
8 changes: 8 additions & 0 deletions backend/config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import os

DATABASE_CONFIG = {
'host': os.getenv('DB_HOST'),
'database': os.getenv('DB_DATABASE'),
'user': os.getenv('DB_USER'),
'password': os.getenv('DB_PASSWORD')
}
49 changes: 49 additions & 0 deletions backend/databaseService.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
from db import get_db_connection

def fetch_all_accounts():
conn = get_db_connection()
if conn:
cursor = conn.cursor(dictionary=True)
cursor.execute('SELECT * FROM accounts')
accounts = cursor.fetchall()
cursor.close()
conn.close()
return accounts, None
else:
return None, "Database connection failed"

def fetch_all_transactions():
conn = get_db_connection()
if conn:
cursor = conn.cursor(dictionary=True)
cursor.execute('SELECT * FROM transactions')
transactions = cursor.fetchall()
cursor.close()
conn.close()
return transactions, None
else:
return None, "Database connection failed"

def insert_transaction(transaction_data):
conn = get_db_connection()
if conn:
cursor = conn.cursor()
cursor.execute(
'INSERT INTO transactions (account_id, bank_name, date, type, payee, amount, category) '
'VALUES (%s, %s, %s, %s, %s, %s, %s)',
(
transaction_data['account_id'],
transaction_data['bank_name'],
transaction_data['date'],
transaction_data['type'],
transaction_data['payee'],
transaction_data['amount'],
transaction_data['category']
)
)
conn.commit()
cursor.close()
conn.close()
return "Transaction added successfully", None
else:
return None, "Database connection failed"
13 changes: 13 additions & 0 deletions backend/db.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import mysql.connector
from mysql.connector import Error
from config import DATABASE_CONFIG

def get_db_connection():
try:
conn = mysql.connector.connect(**DATABASE_CONFIG)
if conn.is_connected():
print("Connected to MySQL database")
return conn
except Error as e:
print(f"Error connecting to MySQL Database: {e}")
return None
33 changes: 33 additions & 0 deletions backend/routes.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
from flask import Blueprint, jsonify, request
from databaseService import fetch_all_accounts, fetch_all_transactions, insert_transaction

api = Blueprint('api', __name__)

@api.route('/health', methods=['GET'])
def health_check():
return jsonify({"message": "Server is running"})

@api.route('/accounts', methods=['GET'])
def get_accounts():
accounts, error = fetch_all_accounts()
if error:
return jsonify({"error": error}), 500
else:
return jsonify({"data": accounts})

@api.route('/transactions', methods=['GET'])
def get_transactions():
transactions, error = fetch_all_transactions()
if error:
return jsonify({"error": error}), 500
else:
return jsonify({"data": transactions})

@api.route('/transactions', methods=['POST'])
def add_transaction():
transaction_data = request.json
message, error = insert_transaction(transaction_data)
if error:
return jsonify({"error": error}), 500
else:
return jsonify({"message": message}), 201
21 changes: 21 additions & 0 deletions backend/tests/test_db.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import unittest
from unittest.mock import patch
from db import get_db_connection
import mysql.connector

class TestDatabaseConnection(unittest.TestCase):

@patch('mysql.connector.connect')
def test_get_db_connection_success(self, mock_connect):
mock_connect.return_value.is_connected.return_value = True
conn = get_db_connection()
self.assertTrue(conn.is_connected())

@patch('mysql.connector.connect')
def test_get_db_connection_failure(self, mock_connect):
mock_connect.side_effect = mysql.connector.Error("Connection failed")
conn = get_db_connection()
self.assertIsNone(conn)

if __name__ == '__main__':
unittest.main()
56 changes: 56 additions & 0 deletions backend/tests/test_routes.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import unittest
from unittest.mock import patch
from app import app

class TestFlaskRoutes(unittest.TestCase):
def setUp(self):
self.app = app.test_client()
self.app.testing = True

def test_health_check(self):
response = self.app.get('/health')
self.assertEqual(response.status_code, 200)
self.assertEqual(response.json, {"message": "Server is running"})

@patch('routes.fetch_all_accounts')
def test_get_accounts(self, mock_fetch_all_accounts):
mock_fetch_all_accounts.return_value = ([
{"id": 1, "name": "Account 1", "balance": 1000},
{"id": 2, "name": "Account 2", "balance": 2000},
], None)

response = self.app.get('/accounts')
self.assertEqual(response.status_code, 200)
self.assertEqual(response.json, {"data": mock_fetch_all_accounts.return_value[0]})

@patch('routes.fetch_all_transactions')
def test_get_transactions(self, mock_fetch_all_transactions):
mock_fetch_all_transactions.return_value = ([
{"id": 1, "account_id": 1, "payee": "Netflix", "amount": -15, "category": "Entertainment"},
{"id": 2, "account_id": 2, "payee": "Grocery Store", "amount": -100, "category": "Groceries"},
], None)

response = self.app.get('/transactions')
self.assertEqual(response.status_code, 200)
self.assertEqual(response.json, {"data": mock_fetch_all_transactions.return_value[0]})

@patch('routes.insert_transaction')
def test_add_transaction(self, mock_insert_transaction):
mock_insert_transaction.return_value = ("Transaction added successfully", None)

transaction_data = {
"account_id": "1",
"bank_name": "Test Bank",
"date": "2022-01-01",
"type": "debit",
"payee": "New Payee",
"amount": 50,
"category": "Test Category",
}

response = self.app.post('/transactions', json=transaction_data)
self.assertEqual(response.status_code, 201)
self.assertEqual(response.json, {"message": "Transaction added successfully"})

if __name__ == '__main__':
unittest.main()
18 changes: 18 additions & 0 deletions frontend/jest.config.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
module.exports = {
preset: "ts-jest",
testEnvironment: "node",
moduleNameMapper: {
"^@/(.*)$": "<rootDir>/src/$1",
},
transform: {
"^.+\\.ts$": "ts-jest",
},
globals: {
"ts-jest": {
useESM: true,
tsconfig: '<rootDir>/tsconfig.spec.json'
},
},
extensionsToTreatAsEsm: [".ts"],
testMatch: ["**/__tests__/**/*.ts?(x)", "**/?(*.)+(spec|test).ts?(x)"],
};
Loading

0 comments on commit 30c675a

Please sign in to comment.