From 367430816ee3211f307d3c45a10a1a40a2936021 Mon Sep 17 00:00:00 2001 From: wwakabobik Date: Thu, 29 Aug 2024 18:21:49 +0200 Subject: [PATCH] Added test_reporter_utils_csv_parser_*.py --- testrail_api_reporter/utils/csv_parser.py | 15 ++--- tests/conftest.py | 66 ++++++++++++++++++- tests/utils/test_reporter_utils_case_stat.py | 66 +++++++++++-------- ...reporter_utils_csv_parser_custom_logger.py | 17 +++++ ...rter_utils_csv_parser_load_history_data.py | 50 ++++++++++++++ ...rter_utils_csv_parser_save_history_data.py | 60 +++++++++++++++++ 6 files changed, 235 insertions(+), 39 deletions(-) create mode 100644 tests/utils/test_reporter_utils_csv_parser_custom_logger.py create mode 100644 tests/utils/test_reporter_utils_csv_parser_load_history_data.py create mode 100644 tests/utils/test_reporter_utils_csv_parser_save_history_data.py diff --git a/testrail_api_reporter/utils/csv_parser.py b/testrail_api_reporter/utils/csv_parser.py index 955543a..39c037e 100644 --- a/testrail_api_reporter/utils/csv_parser.py +++ b/testrail_api_reporter/utils/csv_parser.py @@ -42,14 +42,11 @@ def save_history_data(self, filename=None, report=None): date = datetime.today().strftime("%Y-%m-%d") last_date = "" mode = "r" if exists(filename) else "w" - try: - with open(filename, mode, encoding="utf-8") as csvfile: - if mode == "r": - for row in reversed(list(csv.reader(csvfile))): - last_date = f"{row[0]}-{row[1]}-{row[2]}" - break - except FileNotFoundError: - raise ValueError("Can't open report file, save history data aborted!") from FileNotFoundError + with open(filename, mode, encoding="utf-8") as csvfile: + if mode == "r": + for row in reversed(list(csv.reader(csvfile))): + last_date = f"{row[0]}-{row[1]}-{row[2]}" + break if last_date != date: self.___logger.debug("Last date in file: %s for %s", filename, last_date) with open(filename, "a+", newline="", encoding="utf-8") as csvfile: @@ -69,7 +66,7 @@ def save_history_data(self, filename=None, report=None): else: self.___logger.debug("Data already stored for today, skipping save") - def load_history_data(self, filename=None): + def load_history_data(self, filename=None) -> list[list[datetime], list[str], list[str], list[str]]: """ Load history data to CSV diff --git a/tests/conftest.py b/tests/conftest.py index 904133c..bfff202 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -2,13 +2,16 @@ """Conftest for testsuite""" from os import path, remove +from random import randint import pytest from faker import Faker +from testrail_api_reporter.utils.case_stat import CaseStat # pylint: disable=import-error,no-name-in-module + @pytest.fixture -def create_test_file(): +def create_test_file() -> str: """ Fixture to create random test file @@ -25,3 +28,64 @@ def create_test_file(): remove(test_file) except FileNotFoundError: pass + + +@pytest.fixture +def random_stat() -> tuple[int, int, int, int]: + """ + Fixture to return tuple with random statistics + + :return: tuple with random statistics + :rtype: tuple[int, int, int, int] + """ + total = randint(0, 32768) + automated = randint(0, 32768) + not_automated = randint(0, 32768) + not_applicable = randint(0, 32768) + return total, automated, not_automated, not_applicable + + +@pytest.fixture +def case_stat() -> CaseStat: + """ + Fixture to return object of CaseStat + + :return: CaseStat + :rtype: CaseStat + """ + return CaseStat(Faker().word()) + + +@pytest.fixture +def case_stat_random(case_stat, random_stat): + """ + Fixture to return object of CaseStat + + :return: CaseStat with random statistics + :rtype: CaseStat + """ + total, automated, not_automated, not_applicable = random_stat + case_stat.set_total(total) + case_stat.set_automated(automated) + case_stat.set_not_automated(not_automated) + case_stat.set_not_applicable(not_applicable) + return case_stat + + +@pytest.fixture +def csv_file() -> str: + """ + Fixture to create random test file + + :return: filename + """ + test_file = f"not_existing_{Faker().file_name(extension='csv')}" + with open(test_file, "w", encoding="utf-8") as file: + file.write("") + assert path.exists(test_file) is True + yield test_file + # Cleanup if not removed by tests + try: + remove(test_file) + except FileNotFoundError: + pass diff --git a/tests/utils/test_reporter_utils_case_stat.py b/tests/utils/test_reporter_utils_case_stat.py index 9f407f8..2c69efb 100644 --- a/tests/utils/test_reporter_utils_case_stat.py +++ b/tests/utils/test_reporter_utils_case_stat.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -"""Tests for the reporter_utils module, сlass 'CaseStat'""" +"""Tests for the case_stat module, сlass 'CaseStat'""" import pytest from faker import Faker @@ -19,6 +19,7 @@ def test_case_stat_init(): assert case_stat.not_automated == 0 assert case_stat.not_applicable == 0 + def test_case_stat_name(): """Check name attribute""" name = fake.word() @@ -30,71 +31,78 @@ def test_case_stat_name(): case_stat.set_name(new_name) assert case_stat.get_name() == new_name, "Test case name does not match after change" -def test_case_stat_total(): - """Check total""" - name = fake.word() - case_stat = CaseStat(name) +def test_case_stat_total(case_stat): + """Check total""" total = fake.random_number() case_stat.set_total(total) assert case_stat.get_total() == total, "Total number of test cases does not match" -def test_case_stat_automated(): - """Check automated""" - name = fake.word() - case_stat = CaseStat(name) +def test_case_stat_automated(case_stat): + """Check automated""" automated = fake.random_number() case_stat.set_automated(automated) assert case_stat.get_automated() == automated, "Number of automated test cases does not match" -def test_case_stat_not_automated(): - """Check not automated""" - name = fake.word() - case_stat = CaseStat(name) +def test_case_stat_not_automated(case_stat): + """Check not automated""" not_automated = fake.random_number() case_stat.set_not_automated(not_automated) assert case_stat.get_not_automated() == not_automated, "Number of not automated test cases does not match" -def test_case_stat_not_applicable(): - """Check not applicable""" - name = fake.word() - case_stat = CaseStat(name) +def test_case_stat_not_applicable(case_stat): + """Check not applicable""" not_applicable = fake.random_number() case_stat.set_not_applicable(not_applicable) assert case_stat.get_not_applicable() == not_applicable, "Number of not applicable test cases does not match" -def test_case_stat_negative(): - # Создаем экземпляр клас��а с именем теста - name = fake.word() - case_stat = CaseStat(name) - - # Пытаемся установить отрицательное количество тестов +def test_case_stat_negative_total(case_stat): + """Negative case for total""" with pytest.raises(ValueError): case_stat.set_total(-1) - # Пытаемся установить количество тестов не числовым значением + +def test_case_stat_total_not_a_number(case_stat): + """Negative case for total - incorrect type""" with pytest.raises(TypeError): - case_stat.set_total("not a number") + case_stat.set_total("not a number") # type: ignore - # Повторяем для остальных сеттеров + +def test_case_stat_negative_automated(case_stat): + """Negative case for automated""" with pytest.raises(ValueError): case_stat.set_automated(-1) + +def test_case_stat_automated_not_a_number(case_stat): + """Negative case for automated - incorrect type""" with pytest.raises(TypeError): - case_stat.set_automated("not a number") + case_stat.set_automated("not a number") # type: ignore + +def test_case_stat_negative_not_automated(case_stat): + """Negative case for not_automated""" with pytest.raises(ValueError): case_stat.set_not_automated(-1) + +def test_case_stat_not_automated_not_a_number(case_stat): + """Negative case for not automated - incorrect type""" with pytest.raises(TypeError): - case_stat.set_not_automated("not a number") + case_stat.set_not_automated("not a number") # type: ignore + +def test_case_stat_negative_not_applicable(case_stat): + """Negative case for not applicable""" with pytest.raises(ValueError): case_stat.set_not_applicable(-1) + +def test_case_stat_not_applicable_not_a_number(case_stat): + """Negative case for not applicable - incorrect type""" with pytest.raises(TypeError): - case_stat.set_not_applicable("not a number") \ No newline at end of file + case_stat.set_not_applicable("not a number") diff --git a/tests/utils/test_reporter_utils_csv_parser_custom_logger.py b/tests/utils/test_reporter_utils_csv_parser_custom_logger.py new file mode 100644 index 0000000..ef3efdd --- /dev/null +++ b/tests/utils/test_reporter_utils_csv_parser_custom_logger.py @@ -0,0 +1,17 @@ +# -*- coding: utf-8 -*- +"""Tests for the csv_parser module against custom logger""" + +from logging import Logger, DEBUG, ERROR, FATAL, INFO, WARNING +from random import choice + +from faker import Faker + +from testrail_api_reporter.utils.csv_parser import CSVParser # pylint: disable=import-error,no-name-in-module + + +fake = Faker() + + +def test_custom_csv_logger(): + """Use custom logger""" + CSVParser(logger=Logger(name=fake.name(), level=choice((DEBUG, INFO, WARNING, ERROR, FATAL)))) diff --git a/tests/utils/test_reporter_utils_csv_parser_load_history_data.py b/tests/utils/test_reporter_utils_csv_parser_load_history_data.py new file mode 100644 index 0000000..5970e78 --- /dev/null +++ b/tests/utils/test_reporter_utils_csv_parser_load_history_data.py @@ -0,0 +1,50 @@ +# -*- coding: utf-8 -*- +"""Tests for the csv_parser module, 'load_history' function""" + +from datetime import datetime + +import pytest +from faker import Faker + +from testrail_api_reporter.utils.csv_parser import CSVParser # pylint: disable=import-error,no-name-in-module + + +fake = Faker() + + +def test_load_history_data(csv_file, random_stat): + """Check load_history_data function""" + parser = CSVParser(filename=csv_file) + + total, automated, not_automated, not_applicable = random_stat + year = fake.year() + month = fake.month() + day_of_month = fake.day_of_month() + with open(csv_file, "w") as f: + f.write(f"{year},{month},{day_of_month},{total},{automated},{not_automated},{not_applicable}\n") + + data = parser.load_history_data() + + assert data == [ + [datetime(int(year), int(month), int(day_of_month))], + [str(total)], + [str(automated)], + [str(not_automated)], + [str(not_applicable)], + ] + + +def test_load_history_data_no_filename(csv_file): + """No filename is provided for load history""" + parser = CSVParser() + + with pytest.raises(ValueError): + parser.load_history_data() + + +def test_load_history_data_file_not_found(): + """File not found error for load history""" + parser = CSVParser(filename="non_existent_file.csv") + + with pytest.raises(ValueError): + parser.load_history_data() diff --git a/tests/utils/test_reporter_utils_csv_parser_save_history_data.py b/tests/utils/test_reporter_utils_csv_parser_save_history_data.py new file mode 100644 index 0000000..ae41cda --- /dev/null +++ b/tests/utils/test_reporter_utils_csv_parser_save_history_data.py @@ -0,0 +1,60 @@ +# -*- coding: utf-8 -*- +"""Tests for the csv_parser module'""" +from datetime import datetime + +import pytest +from faker import Faker + +from testrail_api_reporter.utils.csv_parser import CSVParser # pylint: disable=import-error,no-name-in-module + +fake = Faker() + + +def test_save_history_data(csv_file, random_stat, case_stat): + """Check save_history_data function""" + parser = CSVParser(filename=csv_file) + + total, automated, not_automated, not_applicable = random_stat + case_stat.set_total(total) + case_stat.set_automated(automated) + case_stat.set_not_automated(not_automated) + case_stat.set_not_applicable(not_applicable) + + parser.save_history_data(report=case_stat) + + with open(csv_file, "r") as f: + data = f.read() + assert data == ( + f"{datetime.today().strftime('%Y')}," + f"{datetime.today().strftime('%m')}," + f"{datetime.today().strftime('%d')}," + f"{total},{automated},{not_automated},{not_applicable}\n" + ) + + +def test_save_history_data_no_filename(csv_file): + """No filename provided for save history data""" + parser = CSVParser() + + with pytest.raises(ValueError): + parser.save_history_data() + + +def test_save_history_data_no_report(csv_file): + """No data for save history data""" + parser = CSVParser(filename=csv_file) + + with pytest.raises(ValueError): + parser.save_history_data() + + +def test_save_history_data_already_stored(csv_file, random_stat, case_stat_random): + """History already stored for such day for save history data""" + parser = CSVParser(filename=csv_file) + + parser.save_history_data(report=case_stat_random) + parser.save_history_data(report=case_stat_random) + + with open(csv_file, "r") as f: + data = f.read() + assert data.count("\n") == 1