Package: pytest-lambda
pytest-lambdaDefine pytest fixtures with lambda functions.Quickstartpipinstallpytest-lambda# test_the_namerator.pyfrompytest_lambdaimportlambda_fixture,static_fixturefirst=static_fixture('John')middle=static_fixture('Jacob')last=static_fixture('Jingleheimer-Schmidt')full_name=lambda_fixture(lambdafirst,middle,last:f'{first}{middle}{last}')deftest_the_namerator(full_name):assertfull_name=='John Jacob Jingleheimer-Schmidt'Cheatsheetimportasyncioimportpytestfrompytest_lambdaimport(disabled_fixture,error_fixture,lambda_fixture,not_implemented_fixture,static_fixture,)# Basic usagefixture_name=lambda_fixture(lambdaother_fixture:'expression',scope='session',autouse=True)# Async fixtures (awaitables automatically awaited) — requires an async plugin, like pytest-asynciofixture_name=lambda_fixture(lambda:asyncio.sleep(0,'expression'),async_=True)# Request fixtures by namefixture_name=lambda_fixture('other_fixture')fixture_name=lambda_fixture('other_fixture','another_fixture','cant_believe_its_not_fixture')ren,ame,it=lambda_fixture('other_fixture','another_fixture','cant_believe_its_not_fixture')# Reference `self` inside a classclassTestContext:fixture_name=lambda_fixture(lambdaself:self.__class__.__name__,bind=True)# Parametrizefixture_name=lambda_fixture(params=['a','b'])fixture_name=lambda_fixture(params=['a','b'],ids=['A!','B!'])fixture_name=lambda_fixture(params=[pytest.param('a',id='A!'),pytest.param('b',id='B!')])alpha,omega=lambda_fixture(params=[pytest.param('start','end',id='uno'),pytest.param('born','dead',id='dos')])# Use literal value (not lazily evaluated)fixture_name=static_fixture(42)fixture_name=static_fixture('just six sevens',autouse=True,scope='module')# Raise an exception if fixture is requestedfixture_name=error_fixture(lambda:ValueError('my life has no intrinsic value'))# Or maybe don't raise the exceptionfixture_name=error_fixture(lambdaother_fixture:TypeError('nope')ifother_fixtureelseNone)# Create an abstract fixture (to be overridden by the user)fixture_name=not_implemented_fixture()fixture_name=not_implemented_fixture(autouse=True,scope='session')# Disable usage of a fixture (fail early to save future head scratching)fixture_name=disabled_fixture()What else is possible?Of course, you can use lambda fixtures inside test classes:# test_staying_classy.pyfrompytest_lambdaimportlambda_fixtureclassTestClassiness:classiness=lambda_fixture(lambda:9000+1)deftest_how_classy_we_is(self,classiness):assertclassiness==9001Aliasing other fixturesYou can also pass the name of another fixture, instead of a lambda:# test_the_bourne_identity.pyfrompytest_lambdaimportlambda_fixture,static_fixtureagent=static_fixture('Bourne')who_i_am=lambda_fixture('agent')deftest_my_identity(who_i_am):assertwho_i_am=='Bourne'Even multiple fixture names can be used:# test_the_bourne_identity.pyfrompytest_lambdaimportlambda_fixture,static_fixtureagent_first=static_fixture('Jason')agent_last=static_fixture('Bourne')who_i_am=lambda_fixture('agent_first','agent_last')deftest_my_identity(who_i_am):assertwho_i_am==('Jason','Bourne')Destructuring assignment is also supported, allowing multiple fixtures to be renamed in one statement:# test_the_bourne_identity.pyfrompytest_lambdaimportlambda_fixture,static_fixtureagent_first=static_fixture('Jason')agent_last=static_fixture('Bourne')first,last=lambda_fixture('agent_first','agent_last')deftest_my_identity(first,last):assertfirst=='Jason'assertlast=='Bourne'Annotating aliased fixturesYou can force the loading of fixtures without trying to remember the name ofpytest.mark.usefixtures# test_garage.pyfrompytest_lambdaimportlambda_fixture,static_fixturecar=static_fixture({'type':'Sweet-ass Cadillac','is_started':False,})turn_the_key=lambda_fixture(lambdacar:car.update(is_started=True))preconditions=lambda_fixture('turn_the_key',autouse=True)deftest_my_caddy(car):assertcar['is_started']ParametrizingTests can be parametrized withlambda_fixture'sparamskwarg# test_number_5.pyfrompytest_lambdaimportlambda_fixturelady=lambda_fixture(params=['Monica','Erica','Rita','Tina','Sandra','Mary','Jessica'])deftest_your_man(lady):assertlady[:0]in'my life'Destructuring assignment of a parametrized lambda fixture is also supported# test_number_5.pyimportpytestfrompytest_lambdaimportlambda_fixturelady,where=lambda_fixture(params=[pytest.param('Monica','in my life'),pytest.param('Erica','by my side'),pytest.param('Rita','is all I need'),pytest.param('Tina','is what I see'),pytest.param('Sandra','in the sun'),pytest.param('Mary','all night long'),pytest.param('Jessica','here I am'),])deftest_your_man(lady,where):assertlady[:0]inwhereDeclaring abstract thingsnot_implemented_fixtureis perfect for labeling abstract parameter fixtures of test mixins# test_mixinalot.pyimportpytestfrompytest_lambdaimportstatic_fixture,not_implemented_fixtureclassDials1900MixinALot:butt_shape=not_implemented_fixture()desires=not_implemented_fixture()defit_kicks_them_nasty_thoughts(self,butt_shape,desires):assertbutt_shape=='round'and'triple X throw down'indesires@pytest.mark.xfailclassDescribeMissThing(Dials1900MixinALot):butt_shape=static_fixture('flat')desires=static_fixture(['playin workout tapes by Fonda'])classDescribeSistaICantResista(Dials1900MixinALot):butt_shape=static_fixture('round')desires=static_fixture(['gettin in yo Benz','triple X throw down'])Usedisabled_fixtureto mark a fixture as disabled. Go figure.# test_ada.pyimportpytestfrompytest_lambdaimportdisabled_fixturewheelchair=disabled_fixture()@pytest.mark.xfail(strict=True)deftest_stairs(wheelchair):assertwheelchair+'floats'Raising exceptionsYou can also raise an arbitrary exception when a fixture is requested, usingerror_fixture# test_bikeshed.pyimportpytestfrompytest_lambdaimporterror_fixture,not_implemented_fixture,static_fixturebicycle=static_fixture('a sledgehammer')defit_does_sweet_jumps(bicycle):assertbicycle+'jump'>='3 feet'classContextOcean:depth=not_implemented_fixture()bicycle=error_fixture(lambdabicycle,depth:(RuntimeError(f'Now is not the time to use that! ({bicycle})')ifdepth>'1 league'elseNone))classContextDeep:depth=static_fixture('20,000 leagues')@pytest.mark.xfail(strict=True,raises=RuntimeError)defit_doesnt_flip_and_shit(self,bicycle):assertbicycle+'floats'classContextBeach:depth=static_fixture('1 inch')defit_gets_you_all_wet_but_otherwise_rides_like_a_champ(self,bicycle):assert'im wet'Async fixturesBy passingasync_=Truetolambda_fixture, the fixture will be defined as an async function, and if the returned value is awaitable, it will be automatically awaited before exposing it to pytest. This allows the usage of async things while only being slightly salty that Python, TO THIS DAY, still does not supportawaitexpressions within lambdas! Yes, only slightly salty!NOTE: an asyncio pytest plugin is required to use async fixtures, such aspytest-asyncio# test_a_sink.pyimportasyncioimportpytestfrompytest_lambdaimportlambda_fixtureasyncdefhows_the_sink():awaitasyncio.sleep(1)return'leaky'a_sink=lambda_fixture(lambda:hows_the_sink(),async_=True)classDescribeASink:@pytest.mark.asyncioasyncdefit_is_leaky(self,a_sink):asserta_sinkis'leaky'DevelopmentHow can I build and test the thing locally?Create a virtualenv, however you prefer. Or don't, if you prefer.pip install poetrypoetry installto install setuptools entrypoint, so pytest automatically loads the plugin (otherwise, you'll have to runpy.test -p pytest_lambda.plugin)Runpy.test. The tests will be collected from the README.md (thanks topytest-markdown).