Skip to content

Commit

Permalink
modify test, import package right, add AAA description
Browse files Browse the repository at this point in the history
  • Loading branch information
toravest committed May 24, 2025
1 parent 4dafb49 commit a369d4f
Show file tree
Hide file tree
Showing 9 changed files with 112 additions and 97 deletions.
20 changes: 15 additions & 5 deletions tests/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,19 @@ Her er litt info om testene:
- `test_letter_one_day.py` Tester at man får samme data av et sted med stor og liten bokstav.
- `test_one_day.py` Tester at funksjonaliteten for å gjøre om fra unix-timestamp blir den samme som input date.
- `test_test.py` Bare en første test for å sjekke at unittest funker.
- `test_4_one_day.py` Tester om funksjonen fetch_time_data funker som forventet og at dataene som blir hentet er korrekt og identiske med dataen som er skrevet
- `test_clean_data.py` Tester datarensing for nedbør, både snø og regn og konversjon av kelvin til celsius
- `test_fetch_one_day.py` Tester om funksjonen fetch_time_data funker som forventet og at dataene som blir hentet er korrekt og identiske med dataen som er skrevet
- `test_clean_data.py` Tester datarensing for nedbør, både snø og regn og konversjon av kelvin til celsius.
- `test_format_yeardata.py` Tester at kodene i my_package.data er konsistente og gir oss de verdiene vi kan forvente. Bruker mock for å blant annet teste API, dictionary, city. Bruker også mock til å gjøre en negativ test.
- `test_format.py` Testter at API og env er konsistente og satt opp korrekt og inneholder de nøklene man forventer
- `test_input.py` Testter date_to_unix og at den inputen vi får fra bruker returnerer korekt UNIX timestamp, bruker mock til å teste dette
- `test_nordic_cityname.py` Tester at funksjonen replace_nordic gjør at man kan skrive byer med bokstavene æ, ø og å, tester tre ulike byer slik alle bokstavene blir testet
- `test_format.py` Tester at API og env er konsistente og satt opp korrekt og inneholder de nøklene man forventer.
- `test_input.py` Tester date_to_unix og at den inputen vi får fra bruker returnerer korrekt UNIX timestamp, bruker mock til å teste dette
- `test_nordic_cityname.py` Tester at funksjonen replace_nordic gjør at man kan skrive byer med bokstavene æ, ø og å, tester tre ulike byer slik alle bokstavene blir testet

Under utformingen av testene har vi følgt strukturen: Arrange - Act - Assert (AAA).
- Arrange: sette opp alt det nødvendige for å kjøre testen.
- Act: gjennomføre test på testkode, med test variabler.
- Assert: Sette verdien lik forventet utfall, og sjekke om det stemmer.

Et eksempel på denne strukturen finner vi blant annet i `test_letter_one_day.py`:
- Arrange: vi setter opp test-navn, med både små og store bokstaver.
- Act: vi gjennomfører en henting av dataen for begge steder.
- Assert: vi sjekker om begge test-navnene får lik verdi. Altså sjekker vi om stedsnavn er case-sensetiv eller ikke.
31 changes: 0 additions & 31 deletions tests/unit/test_4_one_day.py

This file was deleted.

10 changes: 8 additions & 2 deletions tests/unit/test_clean_data.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
import unittest
import pandas as pd
import numpy as np
from src.my_package.data import extract_city_df
from src.my_package.util import (
import sys
import os

# Add the src folder to the Python path
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '../../src')))

from my_package.data import extract_city_df
from my_package.util import (
kelvin_to_celsius,
ensure_column,
fill_column_0
Expand Down
37 changes: 37 additions & 0 deletions tests/unit/test_fetch_one_day.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import unittest
import sys
import os

# Add the src folder to the Python path
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '../../src')))

from my_package.data import fetch_time_data

class TestFetchOneDay(unittest.TestCase):

def test_fetch_data(self):
# Testdata
#sample_data = {"temperature": 25, "humidity": 60}
city_name = "Oslo"
# start_date = "2025, 03, 25, 11, 00"
start_date = 1742896800
# end_date = "2025, 03, 25, 12, 00"
end_date = 1742900400

# Fetch data from the API, the underscore indicates the folder, which we dont use here
data, _ = fetch_time_data(start_date, end_date, city_name)

# Test if data is collected correctly
# We know the data is stored inside the 'list'
if data and "list" in data and data["list"]:
# Then we know both temp and humidity is stored inside the 'main'
self.assertIn("temp", data["list"][0]["main"])
self.assertIn("humidity", data["list"][0]["main"])
# And we check if wind is in the list
self.assertIn("wind", data["list"][0])
else:
self.fail("No data returned from the API")

if __name__ == "__main__":
unittest.main()

71 changes: 28 additions & 43 deletions tests/unit/test_format_yeardata.py
Original file line number Diff line number Diff line change
@@ -1,22 +1,39 @@
import unittest
import os
import requests
import sys

# Add the src folder to the Python path
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '../../src')))

from unittest.mock import patch
from src.my_package.data import fetch_stat_data
from my_package.data import fetch_stat_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},
# city_id for Maura
'city_id': 3146270,
'result': [
{
"month": 1,
"day": 1,
"temp": {
"record_min": 262.21,
"record_max": 278.3,
"average_min": 269.82,
"average_max": 273.95,
"median": 273.3,
"mean": 272.12,
"p25": 268.21,
"p75": 275.32,
"st_dev": 3.91,
"num": 312
}
}
]
}

Expand All @@ -32,43 +49,11 @@ def test_fetch_data_success(self, mock_get):

# 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))
self.assertIn('city_id', data)
self.assertIn('result', data)

# 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_stat_data(city_name)

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

def test_api_key_in_env(self):
# Check if the API_KEY is loaded from the environment
Expand Down
23 changes: 13 additions & 10 deletions tests/unit/test_input.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,26 +3,29 @@
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")))

from my_package.date_to_unix import from_unix_timestamp # This is the module we are testing
from my_package.date_to_unix import get_unix_timestamp # This is the module we are testing
from my_package.util import CEST_OFFSET


#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"])
@patch('builtins.input', side_effect=["2024, 5, 13, 12, 30", "2024, 5, 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())
expected_start = int(datetime.datetime(2024, 5, 13, 12, 30).timestamp()) + CEST_OFFSET
expected_end = int(datetime.datetime(2024, 5, 14, 15, 45).timestamp()) + CEST_OFFSET

# 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()
unix_start, unix_end = get_unix_timestamp()

# Check that the returned timestamps match the expected values
self.assertEqual(unix_start, expected_start)
Expand All @@ -32,15 +35,15 @@ def test_get_unix_timestamp(self, mock_input):
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)
start_dt = datetime.datetime(2024, 5, 13, 12, 30)
end_dt = datetime.datetime(2024, 5, 14, 15, 45)

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

# 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)
start_from_unix, end_from_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)
Expand Down
2 changes: 1 addition & 1 deletion tests/unit/test_letter_one_day.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
# Add the src folder to the Python path
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '../../src')))

from my_package.fetch_current_data import fetch_current_data
from my_package.data import fetch_current_data

class TestCityNameCase(unittest.TestCase):

Expand Down
7 changes: 6 additions & 1 deletion tests/unit/test_nordic_cityname.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
import unittest
import sys
import os

from src.my_package.util import replace_nordic
# 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")))

from my_package.util import replace_nordic

#test one city for every letter "æøå" to see that they all work
class TestReplaceNordic(unittest.TestCase):
Expand Down
8 changes: 4 additions & 4 deletions tests/unit/test_one_day.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@
import sys
import os
from datetime import datetime
from src.my_package.date_to_unix import from_unix_timestamp

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

from my_package.date_to_unix import from_unix_timestamp
from my_package.util import CEST_OFFSET

class TestGetUnixTimestamp(unittest.TestCase):

Expand All @@ -20,8 +20,8 @@ def test_get_unix_timestamp(self):
end_date = datetime.strptime(end_date_input, "%Y, %m, %d, %H, %M")

# Get the Unix timestamp by calling .timestamp()
expected_unix_start = int(start_date.timestamp())
expected_unix_end = int(end_date.timestamp())
expected_unix_start = int(start_date.timestamp()) + CEST_OFFSET
expected_unix_end = int(end_date.timestamp()) + CEST_OFFSET

# Call the function directly with test data
function_unix_start, function_unix_end = from_unix_timestamp(expected_unix_start, expected_unix_end)
Expand Down

0 comments on commit a369d4f

Please sign in to comment.