Deep understanding of how the pytest-repeat plugin works

As mentioned in the previous article, pytest_repeathow is the specific function of the plug-in realized? I believe that after understanding the plugin in detail, other third-party plugins can quickly understand its internal operating mechanism. 

pytest_repeatHow to implement recurring use cases without using plugins

The most stupid way, of course, is to run multiple times, but this is obviously not what we need. In the decorator review article, we reviewed the knowledge points related to decorators, knowing that decorators can dynamically add functions or modify function behavior without modifying the original code. Obviously, here we can use decorators to achieve repeated functions.

def repeat(nums: int = 2):
  
    def wrapper(func):
​
        @functools.wraps(func)
        def decorator(*args, **kwargs):
            for i in range(nums):
                func(*args, **kwargs)
​
        return decorator
​
    return wrapper

This code is easy to understand. It defines a decorator with custom parameters, indicating the number of times the function inside the decorator is executed. In this way, using the decorator on the use case @repeat()can achieve the purpose of running the use case repeatedly. But the statistical result is still 1 use case. Students who have used it pytest_repeatknow that its statistical results are multiple use cases? How to do that, find out through the source code.

pytest_repeatHow to achieve repeated execution

Direct access to source code

Source code interpretation

def pytest_addoption(parser):
    parser.addoption(
        '--count',
        action='/pytest-dev/pytest-repeat/blob/v0.9.1/store',
        default=1,
        type=int,
        help='Number of times to repeat each test')
​
    parser.addoption(
        '--repeat-scope',
        action='/pytest-dev/pytest-repeat/blob/v0.9.1/store',
        default='function',
        type=str,
        choices=('function', 'class', 'module', 'session'),
        help='Scope for repeating tests')

This code defines two command line options:

  • --count: Used to specify the number of times each test case is to be repeated. action=storeIndicates to store the value in the command line argument.
  • --repeat-scope: Used to specify the scope of repeated test cases, you can choose function, class, moduleor session. The default value is function. action=storeIndicates to store the value in the command line argument.

Both options are parser.addoptionadded to pytest's command-line parser via the method.

When running pytest and specifying --countparameters --repeat-scope, pytest-repeatthe plugin will take those parameters and automatically generate multiple repeated execution instances for the test case.

For example, if you run the following command:

pytest --count=2 --repeat-scope=function

pytest-repeatThe test case will be automatically executed twice when the test case is executed test_my_function.


action=storeis argparsean argument in the module that specifies how the option's value is handled during command-line parsing. Specifically, action=storemeans to store the value of the option in a command-line argument.

When using parser.addoptionthe method to add options to the command-line parser, by specifying action=store, the value of the option will be stored in the parsed result, which can be obtained through the corresponding attribute.

For example, when running the pytest command, the values ​​of the --countand --repeat-scopeoptions specified are stored in the command-line arguments. You can request.config.getoptionaccess these stored values ​​using the method, for example:

def test_example(request):
    count = request.config.getoption('--count') 
    # count = request.config.option.count 这样也能获取
    repeat_scope = request.config.getoption('--repeat-scope')
    # repeat_scope = request.config.option.repeat_scope
    # 使用获取到的值进行后续操作

In the sample code above, the values ​​of and request.config.getoptionare obtained from the command line parameters using the method , and are stored in the and variables respectively.--count--repeat-scopecountrepeat_scope

Summary: action=storeis argparsea parameter in the module that specifies to store the value of the option in the command-line argument. In pytest, request.config.getoptionoption values ​​stored in command-line arguments can be obtained by using the method.


def pytest_configure(config):
    config.addinivalue_line(
        'markers',
        'repeat(n): run the given test function `n` times.')

This function is called during the configure phase of pytest config.addinivalue_line()to add custom flags 'repeat(n)'to pytest's flags list by calling . 'repeat(n)'Flags can be used to specify the number of times a test function should be repeated.


@pytest.fixture
def __pytest_repeat_step_number(request):
    marker = request.node.get_closest_marker("repeat")
    count = marker and marker.args[0] or request.config.option.count
    if count > 1:
        try:
            return request.param
        except AttributeError:
            if issubclass(request.cls, TestCase):
                warnings.warn(
                    "Repeating unittest class tests not supported")
            else:
                raise UnexpectedError(
                    "This call couldn't work with pytest-repeat. "
                    "Please consider raising an issue with your usage.")

This fixture function is used to get the current repeat step number. It first checks if the test function is 'repeat'decorated with a tag and gets the repetition count from the tag. If not flagged, the arguments in the command-line arguments are used --countas defaults.


@pytest.hookimpl(trylast=True)
def pytest_generate_tests(metafunc):
    count = metafunc.config.option.count
    m = metafunc.definition.get_closest_marker('repeat')
    if m is not None:
        count = int(m.args[0])
    if count > 1:
        metafunc.fixturenames.append("__pytest_repeat_step_number")
​
        def make_progress_id(i, n=count):
            return '{0}-{1}'.format(i + 1, n)
​
        scope = metafunc.config.option.repeat_scope
        metafunc.parametrize(
            '__pytest_repeat_step_number',
            range(count),
            indirect=True,
            ids=make_progress_id,
            scope=scope
        )

This pytest_generate_testshook function will be called after all test functions have been collected by pytest, and it is set trylast=Trueto ensure that it is executed after other hook functions have finished executing.

  1. First, the code gets metafunc.config.option.countthe value of , which represents the number of times the test case is repeated.
  2. Then, the code calls metafunc.definition.get_closest_marker('repeat')to get whether the test case has a repeatmarker marked as .
  3. If there is repeata marker of , get the number of repeated executions from the marker and assign it to countthe variable.
  4. Next, the code metafunc.fixturenames.append("__pytest_repeat_step_number")adds a __pytest_repeat_step_numberfixture name to metafuncthe list of fixtures by adding a fixture named .
  5. Afterwards, a helper function is defined make_progress_idfor generating progress identifiers for test cases.
  6. Depending on metafunc.config.option.repeat_scopethe value of , the repeated execution is scoped.
  7. Finally, metafunc.parametrizetest cases are dynamically generated by calling . It takes range(count)as parameter the number of steps to generate to repeat, and indirect=Truesets to be called indirectly when the fixture is loaded. At the same time, the previously defined progress identifier generation function and scope are used to set other options for parameterization.

It can be seen that it is finally realized through parameterization, which is why repeated executions can be regarded as multiple use cases.

at last

I believe you still have a lot of questions after watching me, fixturewhat is it? markWhat is it? What are the parameters request? What is the hook function? parametrizeWhat is parameterization? These questions can be kept for now. We mainly talked about pytest_repeatthe specific implementation logic in this piece, and then led to so many knowledge points. Don’t worry, we will eliminate them one by one later.

Finally: The complete software testing video tutorial below has been sorted out and uploaded, and friends who need it can get it by themselves [Guaranteed 100% free]

Software Testing Interview Documentation

We must study to find a high-paying job. The following interview questions are the latest interview materials from first-tier Internet companies such as Ali, Tencent, and Byte, and some Byte bosses have given authoritative answers. Finish this set The interview materials believe that everyone can find a satisfactory job.

Guess you like

Origin blog.csdn.net/wx17343624830/article/details/132668577