Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Marking subclass affected methods of parent class. #2947

Closed
namezys opened this issue Nov 24, 2017 · 4 comments
Closed

Marking subclass affected methods of parent class. #2947

namezys opened this issue Nov 24, 2017 · 4 comments
Labels
topic: marks related to marks, either the general marks or builtin

Comments

@namezys
Copy link

namezys commented Nov 24, 2017

I tried to create a class with some test methods with a fixture.
I have a special marker with kwargs that can change behaviour the fixture.
And I want to run this tests with different parameters of this marker.

Unfortunately, all subclass share one method and I every mark affected this method.

Small example:

@pytest.mark.my_marker(status="A")
class TestA(object):

    @pytest.mark.my_marker(status="M")
    def test_method(self, task_context):
        pass

@pytest.mark.my_marker(status="B")
class TestB(TestA):
    pass

In result I have 2 tests:

  • TestA. test_method
  • TestB. test_method

But both test have the same marker with kwargs={"status": "B}

As I understand, pytest.markstore marker in function object and mark method even if it is applied to class.
So it setup markers:

  • my_marker(status="M")
  • my_marker(status="A")
  • my_marker(status="B")

In this case ability to mark method and class simultaneously looks useless.

@nicoddemus
Copy link
Member

Hi @namezys thanks for your writing.

As I understand, pytest.markstore marker in function object and mark method even if it is applied to class.

Indeed that's how it works at the moment. There's an ongoing effort to clean up the mark internals to provide a better API and fix some of the problems of the current mark transferring mechanism.

One note: In 3.2.0 there's a new pytestmark attribute. From the CHANGELOG:

Now test function objects have a pytestmark attribute containing a list of marks applied directly to the test function, as opposed to marks inherited from parent classes or modules. (#2516)

Not sure it will help you much, but thought I would mention it.

@nicoddemus nicoddemus added the topic: marks related to marks, either the general marks or builtin label Nov 24, 2017
@RonnyPfannschmidt
Copy link
Member

@nicoddemus an api to consume those marks more nicely is still largely missing however
i hope i can provide a initial preview api for pytest 3.4

@namezys
Copy link
Author

namezys commented Nov 24, 2017

@nicoddemus Thank you for conformation. I think we should write append disclaim about this behaviour into documentation. Unfortunately, my english is ugly.

For my project I've written a small workaround _get_marker. May be it will be helpful for somebody.

Code (with example of using):

def _get_marker(request, marker_name):
    pytestmark = request.node.keywords._markers.get('pytestmark', [])
    marker = next((m for m in pytestmark if m.name == marker_name), None)
    if not marker:
        pytestmark = reversed(request.node.cls.pytestmark)
        marker = next((m for m in pytestmark if m.name == marker_name), None)
    if not marker:
        marker = next((m for m in request.node.module.pytestmark if m.name == marker_name), None)
    return marker


def get_marker_arguments(request, marker_name, *args):
    """
    Get marker arguments if the provided.
    In other case return default values

    :param request: fixture request
    :param marker_name: marker name
    :param args: list of default arguments
    :return: tuple if expected more than one argument or alone argument
    """
    assert len(args) == 1
    marker = _get_marker(request, marker_name)
    if marker:
        assert len(args) == len(marker.args), "Marker %s has invalid arguments" % marker_name
        args = marker.args

    return args[0] if len(args) == 1 else args

Actually, It is not a right solution because I use private attributes. And I'm not sure what will be in case of multiply inheritance.

@RonnyPfannschmidt
Copy link
Member

this one is covered by the upcoming iter_markers apis in the next feature release

the on function changes will be removed in the next breaking release

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
topic: marks related to marks, either the general marks or builtin
Projects
None yet
Development

No branches or pull requests

3 participants