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

Fixture parametrization with a generator #4002

Closed
Kkevsterrr opened this issue Sep 19, 2018 · 5 comments
Closed

Fixture parametrization with a generator #4002

Kkevsterrr opened this issue Sep 19, 2018 · 5 comments
Labels
topic: parametrize related to @pytest.mark.parametrize type: question general question, might be closed after 2 weeks of inactivity

Comments

@Kkevsterrr
Copy link

Kkevsterrr commented Sep 19, 2018

I would like to be able to use a fixture parametrized with a generator.

For example:

def get_dbs():
     """
     Depending on how many tests are running concurrently, not every database
     will be available. Yield a database only if it's available.
     """
     # Rough sketch of the code: 
     while DB_LIST:
         for db in DB_LIST:
             if db.available():
                 # remove db from list, etc
                 yield db
@pytest.fixture(params=get_dbs())
def db(request):
    mydb = request.params
    ... # do stuff

However, it seems that when the params are given a generator, the generator is immediately casted to a list, and the generator is not used. The power of using a generator over a list is it gives you dynamic control of the fixture setup, like how you can do with tests already with parametrize.

You could, of course, use params as a placeholder to retrieve a database, and then dynamically retrieve an available database inside the fixture, but then the fixture name/id is lost to just "db0", instead of the actual useful name of "aurora_database5" (for example).

Am I missing something, or another way to accomplish this? Thanks for your help.

@RonnyPfannschmidt
Copy link
Member

each test would need a new generator for the parameterizazion, so no, this is definitively not the right way - you should layer the availiable dbs differently and allow test to skip early/be generated differently

@RonnyPfannschmidt RonnyPfannschmidt added type: question general question, might be closed after 2 weeks of inactivity topic: parametrize related to @pytest.mark.parametrize labels Sep 19, 2018
@Kkevsterrr
Copy link
Author

Kkevsterrr commented Sep 19, 2018

I'm not sure I understand what you mean that each test would need a new generator for parametrization.

To extend my previous example

# Each of these corresponds to a real, physical resource that each test must use. 
# If multiple test sessions  are running simultaneously, ideally a test will get a database that is available
# instead of having to block to wait for the database to become available. 
DB_LIST = ["aurora_database", "postgres_database", "mysql"]

def get_dbs():
     """
     Depending on how many tests are running concurrently, not every database
     will be available. Yield a database only if it's available.
     """
     # Rough sketch of the code: 
     while DB_LIST:
         for db in DB_LIST:
             if db.available():
                 # remove db from list, etc
                 yield db

@pytest.fixture(params=get_dbs())
def db(request):
    mydb = request.params
    ... # do stuff

def test_db(testdata, db):
    # perform a test on the given db with the given testdata

If two tests are running concurrently on a machine, this will allow each test to have a test_db with correct naming (test_db[data1:aurora_database]) and ensures that no test session is blocking on another test session while waiting for a database to become available.

If you have another suggestion on how to accomplish this goal (support multiple simultaneous test sessions, which must share some limited pool of external resources that preserves test names) I'm game to explore other solutions!

@Zac-HD Zac-HD closed this as completed Dec 9, 2018
@Kkevsterrr
Copy link
Author

@Zac-HD Why was this issue closed? Was there any progress made towards a solution I missed?

Also, @RonnyPfannschmidt, can you clarify your comment? Thanks!

@RonnyPfannschmidt
Copy link
Member

@Kkevsterrr its not possible to correctly manage parametrization having a generator as value, always use a list yourself

@nicoddemus
Copy link
Member

Adding to the explanation, pytest will iterate over the object given to fixture(params= every time it needs to instantiate the fixture, not only once, so you might as well use fixture(params=list(get_dbs())).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
topic: parametrize related to @pytest.mark.parametrize type: question general question, might be closed after 2 weeks of inactivity
Projects
None yet
Development

No branches or pull requests

4 participants