pytest exception none type object is not callable
Asked Answered
C

1

6

In test1.py I have below code

@pytest.fixture(scope="session")
def moduleSetup(request):
    module_setup = Module_Setup()
    request.addfinalizer(module_setup.teardown())
    return module_setup

def test_1(moduleSetup):
    print moduleSetup
    print '...'
    #assert 0

# def test_2(moduleSetup):
#     print moduleSetup
#     print '...'
#     #assert 0

And in conftest.py I have

class Module_Setup:
    def __init__(self):
        self.driver = webdriver.Firefox()

    def teardown(self):
        self.driver.close()

When I run it launches and closes browser.

But I also get error self = <CallInfo when='teardown' exception: 'NoneType' object is not callable>, func = <function <lambda> at 0x104580488>, when = 'teardown'

Also If I want to run both tests test_1 and test_2 with same driver object I need to use scope module or session?

Cytotaxonomy answered 3/5, 2016 at 16:28 Comment(0)
M
5

Regarding the exception

When using request.addfinalizer(), you shall pass in reference to a function.

Your code is passing result of calling that function.

request.addfinalizer(module_setup.teardown())

You shall call it this way:

request.addfinalizer(module_setup.teardown)

Regarding fixture scope

If your fixture allows reuse across multiple test calls, use "session" scope. If it allows reuse only for tests in one module, use "module" scope.

Alternative fixture solution

The way you use the fixtures is not much in pytest style, it rather resembles unittest.

From the code you show it seems, the only think you need is to have running Firefox with driver allowing to use it in your tests, and after being done, you need to close it.

This can be accomplished by single fixture:

@pytest.fixture(scope="session")
def firefox(request):
    driver = webdriver.Firefox()
    def fin():
        driver.close()
    request.addfinalizer(fin)

or even better using @pytest.yield_fixture

@pytest.yield_fixture(scope="session")
def firefox(request):
    driver = webdriver.Firefox()
    yield driver
    driver.close()

The yield is place, where fixture stops executing, yields the created value (driver) to test cases.

After the tests are over (or better, when the scope of our fixture is over), it continues running the instructions following the yield and does the cleanup work.

In all cases, you may then modify your test cases as follows:

def test_1(firefox):
    print moduleSetup
    print '...'

and the moduleSetup fixture becomes completely obsolete.

Manuscript answered 3/5, 2016 at 16:40 Comment(4)
thnx a lot!! for best practices should I create and destroy webdriver instance for each test or I should I use same object for all tests? specially if I want to run tests in parallel using xdist, will be possible with same webdriver object or I need to give scope function to create and destroy for each testCytotaxonomy
@Cytotaxonomy I am not sure, how webdriver behaves in concurrent scenarios, you shall try it. I remember, that setting up the driver takes some time, so I would prefer keeping the scope of it as wide as possible to save the startup time even at costs of not using xdist. I would expect, webdriver will manage concurrent usage, but better check it yourself or create new question focused on this topic.Manuscript
thnx I will run and check best approach. In If your fixture allows reuse across multiple test calls, use scope did you mean to say scope or session?Cytotaxonomy
@Cytotaxonomy Sorry for error, yes, I meant "session" - corrected in my answer.Manuscript

© 2022 - 2024 — McMap. All rights reserved.