Search code examples
pythonautomationpytest

Trying to Avoid code duplications on pytest tests


I have this structure:

@pytest.fixture(scope='session')
def load_config() -> dict:
    with open(r"test_plan_1.yaml") as f:
        data = yaml.safe_load(f)
    return data

class TestBase:
    def calculate_mape_range(self, test_path_1: str, test_path_2: str, window_size: int, threshold: float) -> int:
       
class TestMapeHealthy(TestMapeBase):
    @pytest.mark.parametrize("threshold", THRESHOLD_COMPREHENSION)
    @pytest.mark.parametrize("window_size", WINDOW_SIZE_COMPREHENSION)
    def test_MAPE_for_healthy_(self, threshold: float, window_size: int, load_config: dict) -> str:

        try:
            consecutive_failures = super().calculate_mape_range(
                load_config['test_plan']['test_ids'][VERSION_TAG]['tools']['test_file_ids']['healthy_test_list'][0],
                load_config['test_plan']['test_ids'][VERSION_TAG]['tools']['test_file_ids']['healthy_test_list'][1],
                window_size,
                threshold
            )
            assert consecutive_failures == 0

class TestMapeFaulty(TestMapeBase):
    @pytest.mark.parametrize("threshold", THRESHOLD_COMPREHENSION)
    @pytest.mark.parametrize("window_size", WINDOW_SIZE_COMPREHENSION)
    def test_MAPE_for_faulty_(self, threshold: float, window_size: int, load_config: dict) -> str:

        try:
            consecutive_failures = super().calculate_mape_range(
                load_config['test_plan']['test_ids'][VERSION_TAG]['tools']['test_file_ids']['faulty_test_list'][0],
                load_config['test_plan']['test_ids'][VERSION_TAG]['tools']['test_file_ids']['faulty_test_list'][1],
                window_size,
                threshold
            )
            assert consecutive_failures == 0

I am basically using the same code in both test cases (the differences are that I'm passing different tags in the YAML to the calculate_mape_range and that the assert statement is different, How can I avoid this duplication of code in an elegant Pytest-way?


Solution

  • You could add a couple of additional parameters to your test function and you should be able to cover both cases with a single function:

    @pytest.mark.parametrize("threshold", THRESHOLD_COMPREHENSION)
    @pytest.mark.parametrize("window_size", WINDOW_SIZE_COMPREHENSION)
    @pytest.mark.parametrize("final_key", ...)
    @pytest.mark.parametrize("should_pass", ...)
    def test_MAPE(threshold: float, window_size: int, final_key: str, should_pass: bool, load_config: dict):
    
        consecutive_failures = super().calculate_mape_range(
            load_config['test_plan']['test_ids'][VERSION_TAG]['tools']['test_file_ids'][final_key][0],
            load_config['test_plan']['test_ids'][VERSION_TAG]['tools']['test_file_ids'][final_key][1],
            window_size,
            threshold
        )
    
        if should_pass:
          assert consecutive_failures == 0
        else:
          assert consecutive_failures > 0