diff --git a/.gitignore b/.gitignore index ee730d8..a3c092a 100644 --- a/.gitignore +++ b/.gitignore @@ -4,4 +4,7 @@ rough/ weatherfiles/ weatherfiles.zip FileTree.ini -.vscode/ \ No newline at end of file +.vscode/ +unittests/test_weather_reporter.py +unittests/test_weatherman.py + diff --git a/code_files/weather_app.py b/code_files/weather_app.py index 3973b04..15ed57c 100644 --- a/code_files/weather_app.py +++ b/code_files/weather_app.py @@ -1,5 +1,12 @@ from code_files.weather_parser import WeatherParser from code_files.weather_reporter import WeatherReporter from code_files.report_calculator import ReportCalculator +from code_files.weather_readings import WeatherReading, WeatherExtremes -__all__ = ['WeatherParser', 'WeatherReporter', 'ReportCalculator'] \ No newline at end of file +__all__ = [ + "WeatherParser", + "WeatherReporter", + "ReportCalculator", + "WeatherReading", + "WeatherExtremes", +] diff --git a/unittests/test_report_calculator.py b/unittests/test_report_calculator.py new file mode 100644 index 0000000..e059974 --- /dev/null +++ b/unittests/test_report_calculator.py @@ -0,0 +1,62 @@ +import os +import sys +import unittest + +sys.path.append(os.path.join(os.path.dirname(__file__), "..")) +from code_files.weather_app import ReportCalculator, WeatherReading, WeatherExtremes + +weather_reading1 = WeatherReading("2012-2-1", 9, 3, 36, 34) +weather_reading2 = WeatherReading("2012-2-2", 12, 5, 47, 34) +weather_reading3 = WeatherReading("2012-2-3", 2, -2, 100, 71) +weather_reading4 = WeatherReading("2012-2-4", 0, -2, 76, 74) +weather_reading5 = WeatherReading("2012-2-5", 3, -3, 87, 77) + + +class TestReportCalculator(unittest.TestCase): + @classmethod + def setUpClass(cls): + cls.readings = [ + weather_reading1, + weather_reading2, + weather_reading3, + weather_reading4, + weather_reading5, + ] + cls.report_calculator = ReportCalculator(cls.readings) + + @classmethod + def tearDownClass(cls): + del cls.readings + del cls.report_calculator + + def test_compute_extreme_stats(self): + """Test the compute_extreme_stats method of the ReportCalculator class. + + The purpose of this test is to ensure that the compute_extreme_stats method correctly + calculates the weather extremes based on the input data. + """ + self.weather_extremes = WeatherExtremes( + 12, -3, 100, ["2012", "2", "2"], ["2012", "2", "5"], ["2012", "2", "3"] + ) + self.assertEqual( + self.weather_extremes, self.report_calculator.compute_extreme_stats() + ) + + def test_compute_average_stats(self): + """Test the compute_average_stats method of the ReportCalculator class. + + This test sets up expected values for the avg_max_temp, avg_min_temp and + avg_mean_humidity. It then calls the compute_average_stats method of the + ReportCalculator class and asserts that the returned values match the + expected values. + """ + self.avg_max_temp = 5.2 + self.avg_min_temp = 0.2 + self.avg_mean_humidity = 58 + self.result = (self.avg_max_temp, self.avg_min_temp, self.avg_mean_humidity) + + self.assertEqual(self.report_calculator.compute_average_stats(), self.result) + + +if __name__ == "__main__": + unittest.main(verbosity=2) diff --git a/unittests/test_suite.py b/unittests/test_suite.py new file mode 100644 index 0000000..ea04105 --- /dev/null +++ b/unittests/test_suite.py @@ -0,0 +1,21 @@ +import unittest + +from test_report_calculator import TestReportCalculator +from test_weather_parser import TestWeatherParser +from test_weather_readings import TestWeatherReading + + +def test_suite(): + """This function creates a test suite containing all the test cases + for the ReportCalculator, WeatherParser, and WeatherReadings. + """ + suite = unittest.TestSuite() + suite.addTest(unittest.makeSuite(TestReportCalculator)) + suite.addTest(unittest.makeSuite(TestWeatherParser)) + suite.addTest(unittest.makeSuite(TestWeatherReading)) + + runner = unittest.TextTestRunner(verbosity=2) + print(runner.run(suite)) + + +test_suite() diff --git a/unittests/test_weather_parser.py b/unittests/test_weather_parser.py new file mode 100644 index 0000000..60ab5ee --- /dev/null +++ b/unittests/test_weather_parser.py @@ -0,0 +1,55 @@ +import os +import sys +import unittest +from tempfile import NamedTemporaryFile + +sys.path.append(os.path.join(os.path.dirname(__file__), '..')) +from code_files.weather_parser import WeatherParser +from code_files.weather_readings import WeatherReading + +SAMPLE_DATA = """PKT,Max TemperatureC,Mean TemperatureC,Min TemperatureC,Dew PointC,MeanDew PointC,Min DewpointC,Max Humidity, Mean Humidity, Min Humidity, Max Sea Level PressurehPa, Mean Sea Level PressurehPa, Min Sea Level PressurehPa, Max VisibilityKm, Mean VisibilityKm, Min VisibilitykM, Max Wind SpeedKm/h, Mean Wind SpeedKm/h, Max Gust SpeedKm/h,Precipitationmm, CloudCover, Events,WindDirDegrees +2012-2-1,9,6,3,-4,-5,-7,36,34,31,,,,10.0,7.0,4.0,11,8,,0.0,,,-1 +2012-2-2,12,8,5,0,-4,-7,47,34,24,,,,10.0,7.0,4.0,18,12,,0.0,8,,-1 +2012-2-3,2,1,-2,0,-3,-6,100,71,33,,,,4.0,2.0,0.1,11,4,,13.0,8,Snow,-1 +2012-2-4,0,-0,-2,-4,-4,-5,76,74,71,,,,0.1,0.1,0.1,7,5,,48.0,8,Snow,-1 +2012-2-5,3,0,-3,-0,-3,-6,87,77,70,,,,10.0,6.0,0.1,4,1,,15.0,8,Snow,-1 +""" + +class TestWeatherParser(unittest.TestCase): + @classmethod + def setUpClass(cls): + """Creates a temporary file and populates the SAMPLE_DATA in it for subsequent tests to use.""" + cls.temp_file = NamedTemporaryFile( + delete=False, + mode="w", + newline="", + suffix=".txt", + ) + cls.temp_file_name = cls.temp_file.name + cls.temp_file.write(SAMPLE_DATA) + cls.temp_file_path = os.path.join(os.getcwd(), cls.temp_file_name) + cls.temp_file.close() + cls.weather_parser = WeatherParser() + cls.weather_parser.parse_weather_file(cls.temp_file_name) + + @classmethod + def tearDownClass(cls): + os.remove(cls.temp_file_name) + + def test_parse_weather_file_total_readings(self): + """Tests that the parse_weather_file method reads all readings from the input data.""" + + self.assertEqual(len(self.weather_parser.weather_readings), 5) + + def test_parse_weather_file_values(self): + """Tests that the parse_weather_file method correctly parses the weather data values.""" + + self.assertEqual(self.weather_parser.weather_readings[0], WeatherReading('2012-2-1',9,3,36,34)) + self.assertEqual(self.weather_parser.weather_readings[1], WeatherReading('2012-2-2',12,5,47,34)) + self.assertEqual(self.weather_parser.weather_readings[2], WeatherReading('2012-2-3',2,-2,100,71)) + self.assertEqual(self.weather_parser.weather_readings[3], WeatherReading('2012-2-4',0,-2,76,74)) + self.assertEqual(self.weather_parser.weather_readings[4], WeatherReading('2012-2-5',3,-3,87,77)) + + +if __name__ == "__main__": + unittest.main() diff --git a/unittests/test_weather_readings.py b/unittests/test_weather_readings.py new file mode 100644 index 0000000..2136113 --- /dev/null +++ b/unittests/test_weather_readings.py @@ -0,0 +1,27 @@ +import os +import sys +import unittest + +sys.path.append(os.path.join(os.path.dirname(__file__), "..")) +from code_files.weather_app import WeatherReading + + +class TestWeatherReading(unittest.TestCase): + def test_validate_reading(self): + """Tests the functionality of validate_reading method of WeatherReading class.""" + + self.assertEqual(WeatherReading.validate_reading(10), 10) + self.assertEqual(WeatherReading.validate_reading("10"), 10) + + self.assertEqual(WeatherReading.validate_reading(-4), -4) + self.assertEqual(WeatherReading.validate_reading("-4"), -4) + + self.assertEqual(WeatherReading.validate_reading(0), 0) + self.assertEqual(WeatherReading.validate_reading("0"), 0) + + self.assertIsNone(WeatherReading.validate_reading("")) + self.assertIsNone(WeatherReading.validate_reading(None)) + + +if __name__ == "__main__": + unittest.main()