Christopher Pisz
Christopher Pisz

Reputation: 4010

pytest parameterization based on data obtained from custom classes

How do I parameterize a test function using data that I obtain from other custom classes? In the documentation, I only see examples of parameterizing on static data given as a global list of tuples.

In my case, I am testing a function I wrote that finds a image within another image. It looks like so:

def search_for_image_in_image(screenshot_path, detectable_path):
    """
    Uses template matching algorithm to detect an image within an image
    :param screenshot_path: Path to the screenshot to search
    :param detectable_path: Path to the detectable to search for
    :return: tuple containing:
        (bool) - Whether or not the detectable was found within the screenshot, using
            the given epsilon
        (float) - Maximum value the algorithm found
        (list) - x and y position in the screenshot where the maximum value is located. 
            Or in other words, where the algorithm thinks the top left of the detectable
            is most likely to be (if it is there at all)  

So, I set up some sample data to test with:

tests\
    sample data\
        images_to_search_for\
            moe.png
            larry.png
            curly.png
        images_to_search
            screenshot_01.png
            screenshot_02.png
        expected_results.csv

I manually created the csv file like so:

screenshot_name,moe,larry,curly
screenshot_01,True,False,True       
screenshot_02,False,False,False

I can create classes or functions to load this sample data, but I don't understand how I am to pass it to my test method.

Here is the skeleton of my test code:

import pytest
from image_detection import search_for_image_in_image

class DataLoader(object):
    def __init__(self):
        # Load all the data up
        pass

    def get_screenshot_paths(self):
        """
        :return:  (list of string) paths to all the images to search
        """
        pass

    def get_detectable_paths(self):
        """
        :return: (list of string) paths to all the images to search for
        """
        pass

    def is_expected_to_be_found(self, screenshot_name, detectable_name):
        """
        :param screenshot_name:
        :param detectable_name:
        :return: Whether or not the detectable is expected to be found in the screenshot
        """
        pass


@pytest.mark.parametrize("screenshot_path,detectable_path,expected_result", ???? )
def test_image_searching(screenshot_path, detectable_path, expected_result):
    actual_result, _, _  = search_for_image_in_image(screenshot_path, detectable_path)

What do I put where I have "????" Or do I go about it some other way?

Upvotes: 0

Views: 208

Answers (2)

Guy
Guy

Reputation: 50819

You need to create a function to handle the data

def data_provider():
    data_loader = DataLoader()
    yield pytest.param(data_loader.get_screenshot_paths(), data_loader.get_detectable_paths(), data_loader.is_expected_to_be_found('name_a', 'name_b'))

@pytest.mark.parametrize('screenshot_path, detectable_path, expected_result', data_provider())
def test_image_searching(self, screenshot_path, detectable_path, expected_result):
    actual_result, _, _  = search_for_image_in_image(screenshot_path, detectable_path)

Upvotes: 0

nikhilesh_koshti
nikhilesh_koshti

Reputation: 403

I got your point. What I understand from your question is you want to parametrize the test methods from the return value of other functions, that you are unable to see in the pytest docs.

For that, You have to use pytest hook function(pytest_generate_tests) to parametrize the tests methods.

    import pytest

    def pytest_generate_tests(metafunc):
        """
        This method will call before the execution of all the tests methods.
        """
        #   your logic here, to obtain the value(list data type) from any other      custom classes.
        #   for e.g:-
        data_loader = DataLoader()
        images_path  = data_loader.get_screenshot_paths()
        images_path_1 = data_loader.get_detectable_paths()
        metafunc.parametrize("first_path","seconds_path", images_path, images_path_1)
        # now, whenever this method will called by test methods, it will automatically parametrize with the above values. 



    def test_1(first_path, second_path):
        """
        Your tests method here
        """

I hope you find your answer. Refer(https://docs.pytest.org/en/latest/parametrize.html)

Upvotes: 1

Related Questions