0

I have a class which I would like to instantiate using different sets of input parameters, comparing a property on the resultant object to a passed in value.

I am using the indirect flag on @pytest.fixture for the arguments which are sent to the class constructor. I am trying to unpack kwargs in the constructor. Unsuccesfully. This is the error:

TypeError: type object argument after ** must be a mapping, not SubRequest

Code:

import pytest

class MyClass:
    def __init__(self, a):
        self.a = a

@pytest.fixture
def my_object(request):
    yield MyClass(**request)

# first element = arguments to MyClass, second element = value to compare test to
TEST_CASES = [({"a":1}, 1)]

@pytest.mark.parametrize("test, expected", TEST_CASES, indirect=["test"])
def test_1(my_object, test, expected):
    assert my_object.a == expected

My goal is to have the object arguments and their test value TEST_CASES in one structure for easy inspection

GlaceCelery
  • 921
  • 1
  • 13
  • 30
  • 2
    Two issues: 1. `my_object` has to be named `test` in order for indirect parametrization to work and 2. `request` is a fixture, not test parameters. Access them via `request.param`. – hoefling Oct 01 '18 at 18:03
  • Perfect. Let's say I have MyClass2 and I need to pass that object in to the test as well. Case (1) MyClass2 doesn't need to be parameterised and (2) It does....how do I make pytest do that? – GlaceCelery Oct 01 '18 at 21:11
  • 1
    Please provide a [mcve]. – hoefling Oct 01 '18 at 21:56
  • Thank you. I have raised a new question: [link](https://stackoverflow.com/questions/52599849/passing-more-than-one-argument-to-instantiate-more-than-one-object-in-pytest) – GlaceCelery Oct 01 '18 at 22:42

1 Answers1

0

I've suggest you a working example. Problem was in test code design. The parameter indirect should be True. Indirect parametrization with multiple fixtures should be done as described in docs. And fixture got all params in his request.param attribute.

import pytest


class MyClass:
    def __init__(self, a):
        self.a = a


@pytest.yield_fixture
def test_case(request):
    params, expected = request.param
    yield MyClass(**params), expected


# first element = arguments to MyClass, second element = value to compare test to
TEST_CASES = [({"a": 1}, 1)]


@pytest.mark.parametrize("test_case", TEST_CASES, indirect=True)
def test_1(test_case):
    my_object, expected = test_case
    assert my_object.a == expected
Sergei Voronezhskii
  • 2,184
  • 19
  • 32
  • Thank you Sergey. I only want to pass some arguments to the object fixture, the other argument goes to the test. I went with hoefling's answer. I do have a further question here: https://stackoverflow.com/questions/52599849/passing-more-than-one-argument-to-instantiate-more-than-one-object-in-pytest – GlaceCelery Oct 03 '18 at 11:20
  • You may also wish to have a look at "parameter fixture" instead of using `indirect`. It is a bit more elegant IMHO. https://stackoverflow.com/a/55394178/7262247 – smarie Mar 28 '19 at 09:34