Skip to content

Commit

Permalink
Merge pull request #12 from torave/hanne
Browse files Browse the repository at this point in the history
Hanne - tests
  • Loading branch information
torave authored and GitHub Enterprise committed Apr 20, 2025
2 parents 465eb75 + 1e2b69f commit 5db8517
Show file tree
Hide file tree
Showing 4 changed files with 299 additions and 0 deletions.
103 changes: 103 additions & 0 deletions tests/unit/test_clean_data.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
import unittest
import pandas as pd
import numpy as np
from src.my_package.util import (
kelvin_to_celsius,
ensure_rain_column,
ensure_snow_column,
fill_rain_column,
fill_snow_column,
extract_city_df
)

class TestUtilFunctions(unittest.TestCase):

# Test kelvin to celsius conversion
def test_kelvin_to_celsius(self):
kelvin_temp = 300
expected_celsius = 26.85

result = kelvin_to_celsius(kelvin_temp)

self.assertAlmostEqual(result, expected_celsius, places=2)

# Test if 'rain.1h' column is added when not present
def test_ensure_rain_column(self):
df = pd.DataFrame({
'temp': [300, 302, 305],
'humidity': [80, 82, 78]
})

df = ensure_rain_column(df)

# Check if the 'rain.1h' column is present after function call
self.assertTrue('rain.1h' in df.columns)
# Check if the column has NaN values
self.assertTrue(df['rain.1h'].isna().all())

# Test if 'snow.1h' column is added when not present
def test_ensure_snow_column(self):
df = pd.DataFrame({
'temp': [300, 302, 305],
'humidity': [80, 82, 78]
})

df = ensure_snow_column(df)

# Check if the 'snow.1h' column is present after function call
self.assertTrue('snow.1h' in df.columns)
# Check if the column has NaN values
self.assertTrue(df['snow.1h'].isna().all())

# Test if NaN values in 'rain.1h' are filled with 0
def test_fill_rain_column(self):
df = pd.DataFrame({
'temp': [300, 302, 305],
'rain.1h': [np.nan, 1.0, np.nan]
})

df = fill_rain_column(df)

# Check if NaN values are replaced with 0
self.assertEqual(df['rain.1h'].iloc[0], 0)
self.assertEqual(df['rain.1h'].iloc[2], 0)

# Test if NaN values in 'snow.1h' are filled with 0
def test_fill_snow_column(self):
df = pd.DataFrame({
'temp': [300, 302, 305],
'snow.1h': [np.nan, 0.5, np.nan]
})

df = fill_snow_column(df)

# Check if NaN values are replaced with 0
self.assertEqual(df['snow.1h'].iloc[0], 0)
self.assertEqual(df['snow.1h'].iloc[2], 0)

# Test extracting city DataFrame from JSON data
def test_extract_city_df(self):
weather_data = {
"list": [
{"dt": 1618245600, "temp": 290, "humidity": 85, "weather": [{"description": "clear sky"}]},
{"dt": 1618255600, "temp": 295, "humidity": 80, "weather": [{"description": "cloudy"}]},
{"dt": 1618265600, "temp": 300, "humidity": 75, "weather": [{"description": "sunny"}]}
]
}

df = extract_city_df(weather_data)

# Ensure that 'dt' is the index and in datetime format
self.assertTrue(pd.api.types.is_datetime64_any_dtype(df.index))

# Check if duplicates are removed based on 'dt'
self.assertEqual(len(df), 3)

# Check if 'weather' column was dropped
self.assertNotIn('weather', df.columns)

# Check the correct conversion of 'dt' to datetime
self.assertEqual(df.index[0], pd.to_datetime(1618245600, unit='s'))

if __name__ == '__main__':
unittest.main()
63 changes: 63 additions & 0 deletions tests/unit/test_format.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import unittest
import os

# Function to check if the .env file is created correctly
def check_env_file_creation():
env_filepath = os.path.join(os.path.dirname(__file__), "../../.env")

# Check if the .env file exists
if not os.path.exists(env_filepath):
return False, f".env file does not exist at {env_filepath}"

# Check if the file contains the expected keys
with open(env_filepath, 'r') as env_file:
file_content = env_file.read()

if 'API_EMAIL' not in file_content or 'API_KEY' not in file_content:
return False, "The .env file is missing 'API_EMAIL' or 'API_KEY'."

return True, ".env file is correctly created with API credentials."

# Function to check if the API_EMAIL and API_KEY values are formatted correctly
def check_api_credentials():
env_filepath = os.path.join(os.path.dirname(__file__), "../../.env")

with open(env_filepath, 'r') as env_file:
lines = env_file.readlines()

api_email = None
api_key = None

for line in lines:
if 'API_EMAIL' in line:
api_email = line.strip().split('=')[1].strip().replace('"', '')
elif 'API_KEY' in line:
api_key = line.strip().split('=')[1].strip().replace('"', '')

if not api_email or not api_key:
return False, "API_EMAIL or API_KEY is missing or formatted incorrectly."

# Validate the email format (basic validation for '@' symbol)
if '@' not in api_email:
return False, "API_EMAIL format is incorrect."

# Validate API_KEY length (assuming it's a standard length for OpenWeatherMap keys)
if len(api_key) < 32: # OpenWeatherMap keys are typically longer
return False, "API_KEY format is incorrect."

return True, "API credentials are valid and properly formatted."

class TestDataFormatConsistency(unittest.TestCase):

# Test if the .env file is created correctly
def test_env_file_creation(self):
valid, message = check_env_file_creation()
self.assertTrue(valid, message)

# Test if the API credentials are correct
def test_api_credentials(self):
valid, message = check_api_credentials()
self.assertTrue(valid, message)

if __name__ == '__main__':
unittest.main()
82 changes: 82 additions & 0 deletions tests/unit/test_format_yeardata.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
import unittest
import os
import requests
from unittest.mock import patch
from src.my_package.year_data import fetch_data

class TestDataFormatConsistency(unittest.TestCase):

@patch('requests.get')
def test_fetch_data_success(self, mock_get):
# Sample valid response data structure for the API
mock_data = {
'city': {
'name': 'Maura',
'country': 'NO'
},
'data': [
{'year': 2020, 'temperature': 12.5, 'precipitation': 100},
{'year': 2021, 'temperature': 13.0, 'precipitation': 120},
]
}

# Mock the API response
mock_response = unittest.mock.Mock()
mock_response.status_code = 200
mock_response.json.return_value = mock_data

mock_get.return_value = mock_response

city_name = 'Maura'
data, folder = fetch_data(city_name)

# Check if the data returned is a dictionary and contains the expected keys
self.assertIsInstance(data, dict)
self.assertIn('city', data)
self.assertIn('data', data)

# Check if the 'city' key contains the expected structure
self.assertIn('name', data['city'])
self.assertIn('country', data['city'])

# Check if the 'data' key contains a list of dictionaries with required fields
self.assertIsInstance(data['data'], list)
self.assertGreater(len(data['data']), 0) # Check that there is at least one year record

for record in data['data']:
self.assertIn('year', record)
self.assertIn('temperature', record)
self.assertIn('precipitation', record)
self.assertIsInstance(record['year'], int)
self.assertIsInstance(record['temperature'], (int, float))
self.assertIsInstance(record['precipitation'], (int, float))

# Test that the folder variable exists and is a valid path
self.assertEqual(folder, "../data/output_statistikk")

@patch('requests.get')
def test_fetch_data_failure(self, mock_get):
# Mock an unsuccessful response (non-200 status code)
mock_response = unittest.mock.Mock()
mock_response.status_code = 404
mock_response.json.return_value = {}

mock_get.return_value = mock_response

city_name = 'Maura'
data, folder = fetch_data(city_name)

# Ensure data is empty and folder is correct even on failure
self.assertEqual(data, {})
self.assertEqual(folder, "../data/output_statistikk")

def test_api_key_in_env(self):
# Check if the API_KEY is loaded from the environment
api_key = os.getenv("API_KEY")

self.assertIsNotNone(api_key, "API_KEY is not set in the environment.")
self.assertIsInstance(api_key, str)
self.assertGreater(len(api_key), 0, "API_KEY should not be an empty string.")

if __name__ == '__main__':
unittest.main()
51 changes: 51 additions & 0 deletions tests/unit/test_input.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import unittest
from unittest.mock import patch
import datetime
import sys
import os
from src.my_package import date_to_unix # This is the module we are testing

# This will make the absolute path from the root of the project, and will therefore work every time
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), "../../src")))


#the goal for this test is to simulate user input and check if the returned UNIX timestamps are correct, for this we use mock input

class TestDateToUnix(unittest.TestCase):

@patch('builtins.input', side_effect=["2024, 4, 13, 12, 30", "2024, 4, 14, 15, 45"])
def test_get_unix_timestamp(self, mock_input):
_ = mock_input

# Expected UNIX timestamps for the hardcoded inputs
expected_start = int(datetime.datetime(2024, 4, 13, 12, 30).timestamp())
expected_end = int(datetime.datetime(2024, 4, 14, 15, 45).timestamp())

# Call the function which uses input() — the @patch above mocks input to return predefined values
unix_start, unix_end = date_to_unix.get_unix_timestamp()

# Check that the returned timestamps match the expected values
self.assertEqual(unix_start, expected_start)
self.assertEqual(unix_end, expected_end)

# test the function to ensure it correctly convert timestamp back to datetime
def test_from_unix_timestamp(self):

# Create known datetime objects
start_dt = datetime.datetime(2024, 4, 13, 12, 30)
end_dt = datetime.datetime(2024, 4, 14, 15, 45)

# Convert these to UNIX timestamps
unix_start = int(start_dt.timestamp())
unix_end = int(end_dt.timestamp())

# Use the function to convert them back to datetime
start_from_unix, end_from_unix = date_to_unix.from_unix_timestamp(unix_start, unix_end)

# Assert that the conversion back to datetime matches the original values
self.assertEqual(start_from_unix, start_dt)
self.assertEqual(end_from_unix, end_dt)

# Run all tests in this file when the script is executed directly
if __name__ == '__main__':
unittest.main()

0 comments on commit 5db8517

Please sign in to comment.