pytest - >如何在类

时间:2016-06-11 05:39:48

标签: python python-3.x automated-tests pytest python-unittest

我有一个返回如下值的灯具:

import pytest

@pytest.yield_fixture(scope="module")
def oneTimeSetUp(browser):
    print("Running one time setUp")
    if browser == 'firefox':
        driver = webdriver.Firefox()
        print("Running tests on FF")
    else:
        driver = webdriver.Chrome()
        print("Running tests on chrome")
    yield driver
    print("Running one time tearDown")

此夹具从另一个正在读取命令行选项的夹具中获取浏览器值。

然后我有一个测试类,我有多个测试方法,他们都想使用相同的返回值驱动程序来进行测试。

import pytest

@pytest.mark.usefixtures("oneTimeSetUp")
class TestClassDemo():

    def test_methodA(self):
        # I would like to use the driver value here
        # How could I do this?
        # Something like this
        self.driver.get("https://www.google.com")
        self.driver.find_element(By.ID, "some id")
        print("Running method A")

    def test_methodB(self):
        print("Running method B")

使用self.driver失败并显示错误消息

self = <test_class_demo.TestClassDemo object at 0x102fb6c18>

    def test_methodA(self):
>       self.driver.get("https://www.google.com")
E           AttributeError: 'TestClassDemo' object has no attribute 'driver'

我知道我可以将夹具作为参数传递给我想要使用它的每个方法,但这不是最好的方法,因为我需要在每个方法中使用它并且应该可以将它传递给类然后在所有测试方法中使用它。

我可以将驱动程序对象用于方法的最佳方法是什么?

编辑1:

按照建议

在conftest.py中创建了夹具
@pytest.yield_fixture(scope="class") # <-- note class scope
def oneTimeSetUp(request, browser): # <-- note the additional `request` param
    print("Running one time setUp")
    if browser == 'firefox':
        driver = webdriver.Firefox()
        driver.maximize_window()
        driver.implicitly_wait(3)
        print("Running tests on FF")
    else:
        driver = webdriver.Chrome()
        print("Running tests on chrome")

    ## add `driver` attribute to the class under test -->
    if request.cls is not None:
        request.cls.driver = driver
    ## <--

    yield driver
    print("Running one time tearDown")

我还有一个类,TestClassDemo中有需要的对象,我需要将相同的驱动程序实例传递给类。将其视为ABC类

class ABC():

    def __init(self, driver):
        self.driver = driver

    def enterName(self):
        # Do something with driver instance

然后在TestClassDemo

@pytest.mark.usefixtures("oneTimeSetUp", "setUp")
class TestClassDemo(unittest.TestCase):

    # I need to create an object of class ABC, so that I can use it here
    # abc = ABC(self.driver)

    @pytest.fixture(scope="class", autouse=True)
    def setup(self):
        self.abc = ABC(self.driver)
    # I tried this, but it's not working
    # This error message shows up
    # AttributeError: 'TestClassDemo' object has no attribute 'driver'

    def setup_module(self):
    self.abc = ABC(self.driver)
    # This also does not work
    # Error message ->  AttributeError: 'TestClassDemo' object has no attribute 'abc'


    def test_methodA(self):
        self.driver.get("https://google.com")
        self.abc.enterName("test")
        print("Running method A")

    def test_methodB(self):
        self.abc.enterName("test")
        print("Running method B")

此abc对象也应该可用于其他test_方法。

所有这些类都在不同的模块中,我的意思是在单独的.py文件中说。

另外请在答案中解释使用的最佳方法是什么,而不是使用yield驱动程序实例。

编辑2:

对于没有屈服的这个例子,运行oneTimeTearDown的最佳方法是什么?我在yield

之后运行了tearDown步骤
@pytest.fixture(scope="class")
def oneTimeSetUp(request, browser):
    print("Running one time setUp")
    if browser == 'firefox':
        driver = webdriver.Firefox()
        driver.maximize_window()
        driver.implicitly_wait(3)
        print("Running tests on FF")
    else:
        driver = webdriver.Chrome()
        print("Running tests on chrome")

    if request.cls is not None:
        request.cls.driver = driver

我也尝试使用UnitTest类,但是当我使用def setUpClass(cls)时,我无法使用test_方法中实例化的对象。所以我无法弄清楚如何实现这一点。

我还想从命令行提供像浏览器这样的命令行参数,当我尝试使用unittest时,我不得不在每个类中编写命令行参数。我想只在一个地方提供它们,就像测试套件一样。所以在这里对我有所帮助。

我对stackoverflow有疑问,但没有得到回复。你能看一下吗? Python unittest passing arguments to parent test class

由于

由于

1 个答案:

答案 0 :(得分:2)

py.text unittest integration documentation中概述的一种技术可能会对您有所帮助......使用内置的request灯具。否则,我不知道如何在不提供命名fixture作为方法参数的情况下访问fixture的返回值。

@pytest.yield_fixture(scope="class") # <-- note class scope
def oneTimeSetUp(request, browser): # <-- note the additional `request` param
    print("Running one time setUp")
    if browser == 'firefox':
        driver = webdriver.Firefox()
        print("Running tests on FF")
    else:
        driver = webdriver.Chrome()
        print("Running tests on chrome")

    ## add `driver` attribute to the class under test -->
    if request.cls is not None:
        request.cls.driver = driver
    ## <--

    yield driver
    print("Running one time tearDown")

现在,您可以在driver中作为类属性访问TestClassDemo,就像您的示例中所示(即self.driver应该有效)。

需要注意的是,您的灯具必须使用scope='class',否则request对象将不具有cls属性。

我希望有所帮助!

<强>更新

  

我还有一个类,TestClassDemo中有需要的对象,我需要将相同的驱动程序实例传递给类。将其视为ABC类

如果没有更多的上下文,很难知道,但在我看来,你可以在实例化ABC的同时实例化一个driver对象。 {1}}夹具。例如......

oneTimeSetUp

但是如果你只需要一个或两个测试类的ABC实例,那么你可以在类定义中使用一个fixture ......

@pytest.yield_fixture(scope="class")
def oneTimeSetUp(request, browser):
    print("Running one time setUp")
    if browser == 'firefox':
        driver = webdriver.Firefox()
        driver.maximize_window()
        driver.implicitly_wait(3)
        print("Running tests on FF")
    else:
        driver = webdriver.Chrome()
        print("Running tests on chrome")

    if request.cls is not None:
        request.cls.driver = driver
        request.cls.abc = ABC(driver) # <-- here

    yield driver
    print("Running one time tearDown")

我对第二个例子不会特别满意。第三种选择是使另一个yield_fixture或类似的,与@pytest.mark.usefixtures("oneTimeSetUp", "setUp") class TestClassDemo(unittest.TestCase): @pytest.fixture(autouse=True) def build_abc(self, oneTimeSetUp): # <-- note the oneTimeSetup reference here self.abc = ABC(self.driver) def test_methodA(self): self.driver.get("https://google.com") self.abc.enterName("test") print("Running method A") def test_methodB(self): self.abc.enterName("test") print("Running method B") 完全分开,并返回一个已经包装过驱动程序的ABC实例。

哪种方式最适合您?不确定。您需要根据您的工作情况来决定。

值得注意的是,对于后人来说,pytest灯具只是糖和一点魔力。如果您觉得困难,则根本不需要使用它们。 pytest很乐意执行vanilla unittest TestCases。

  

另外请在答案中解释使用的最佳方法是什么,而不是使用yield驱动程序实例。

这就是我的想法......

oneTimeSetUp

...请注意,这不会返回(或产生)驱动程序对象,这意味着将此fixture作为命名参数提供给函数/方法不再有用,如果你的所有测试用例写成类(由您的示例建议)。

但是,如果要将fixture用作命名参数,请不要这样做。