pytest->如何在类下的测试方法中使用夹具返回值 [英] pytest -> How to use fixture return value in test method under a class

查看:167
本文介绍了pytest->如何在类下的测试方法中使用夹具返回值的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个夹具,它返回的值是这样的:

I have a fixture that returns a value like this:

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")

此设备从另一个正在读取命令行选项的设备获取浏览器值.

This fixture gets the browser value from another fixture which is reading the command line option.

然后我有一个测试类,其中有多个测试方法,并且它们都希望使用相同的返回值驱动程序来进行测试.

Then I have a test class where I have more than one test methods and they all want to consume the same returned value driver to proceed the tests.

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失败并显示错误消息

Using self.driver fails with the error message

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'

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

I am aware that I can pass the fixture as an argument to every method where I want to use that, but that is not the best way because I need this in every method and it should be possible to pass it to the class and then use it in all the test methods.

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

What is the best way that I can make the driver object available to the methods?

按照建议在conftest.py中创建夹具

Created the fixture in conftest.py like this as suggested

@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类

I have one more class, which object in need in the TestClassDemo and I need to pass the same driver instance to the class. Consider it as class ABC

class ABC():

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

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

然后在TestClassDemo中

Then in the 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_方法中可用.

This abc object should be usable in other test_ methods also.

所有这些类均在单独的模块中,我的意思是在单独的.py文件中.

也请在答案中说明什么是代替yield driver实例的最佳使用方法.

Also please explain in the answer what is the best way to use instead of yield driver instance.

对于这个没有收益的例子,什么也是运行oneTimeTearDown的最佳方法?我在收益率之后运行了tearDown步骤

For this example without yield, what would be the best way to run oneTimeTearDown also? I was running the tearDown steps after the yield

@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_方法中实例化的对象.所以我不知道该怎么实现.

Also I tried using UnitTest class, but when I use def setUpClass(cls), I was not able to use the objects instantiated in the test_ methods. So I couldn't not figure out how to achieve that.

我还想从命令行提供诸如浏览器之类的命令行参数,当我尝试进行单元测试时,我不得不在每个类中编写命令行参数.我只想在一个地方提供它们,例如测试套件.所以比赛在这里帮助了我.

I also wanted to provide command line arguments like browser from the command line and when I tried unittest, I had to write the command line argument in every class. I wanted to provide them in one place only, like a test suite. So conftest helped me here.

我对stackoverflow有疑问,但没有得到答复.您还可以看看吗? 将参数传递给父测试类的Python unittest

I had a question on stackoverflow but didn't get a response. Could you please take a look at that also? Python unittest passing arguments to parent test class

谢谢

谢谢

推荐答案

py中概述了一种技术.文本单元测试集成文档,可能对您有帮助...使用内置的request固定装置.否则,如果不提供命名的夹具作为方法参数,我将无法知道访问夹具返回值的方法.

There's a technique outlined in the py.text unittest integration documentation that may be helpful to you ... using the built-in request fixture. Otherwise, I'm not aware of way to access the return value of a fixture without providing the named fixture as a method param.

@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")

现在,您可以像在示例中一样在TestClassDemo中将driver作为类属性进行访问(即self.driver应该可以使用).

Now you can access the driver as a class attribute in TestClassDemo, as you have in your example (i.e. self.driver should work).

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

The caveat is that your fixture must use scope='class', otherwise the request object will not possess a cls attribute.

希望对您有帮助!

更新

我还有一个类,该类在TestClassDemo中是需要的,我需要将相同的驱动程序实例传递给该类.认为它是ABC类

I have one more class, which object in need in the TestClassDemo and I need to pass the same driver instance to the class. Consider it as class ABC

在没有更多上下文的情况下很难知道,但是在我看来,您可以在实例化oneTimeSetUp固定装置中的driver ...的同时实例化ABC对象.例如...

It's difficult to know without more context, but it seems to me that you can probably get away with instantiating an ABC object at the same time that you instantiate the driver ... in the oneTimeSetUp fixture. For example ...

@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")

但是,如果您只需要一个或两个测试类的ABC实例,则可以在类定义中使用固定装置...

But if you only need the ABC instance for a test class or two, here's how you might use a fixture inside the class definition ...

@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")

对于第二个示例,我不会特别满意.第三种选择是使用另一个yield_fixture或类似的东西,它与oneTimeSetUp完全分开,并返回一个已经包装了驱动程序的ABC实例.

I wouldn't be particularly happy with the second example. A third option would be to have another yield_fixture, or similar, that is completely separate from oneTimeSetUp and returns an ABC instance with the driver already wrapped.

哪种方式最适合您?没有把握.您需要根据自己的工作来决定.

Which way is best for you? Not sure. You'll need to decide based on what you're working with.

对于后代来说,适当的注意是pytest固定装置只是糖和一些魔术.如果发现它们很困难,则根本不需要使用它们. pytest很高兴执行香草单元测试TestCases.

It's proper to note for posterity that pytest fixtures are just sugar and a bit of magic. You are not required to use them at all, if you find them difficult. pytest is happy to execute vanilla unittest TestCases.

也请在答案中说明什么是代替yield driver实例的最佳使用方法.

Also please explain in the answer what is the best way to use instead of yield driver instance.

这就是我的想法...

Here's what I had in mind ...

@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

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

... notice that this doesn't return (or yield) the driver object, which means that it's no longer useful to provide this fixture as a named parameter to a function/method, which should be fine if all of your test cases are written as classes (suggested by your examples).

但是,如果要使用灯具作为命名参数,则不要这样做.

However, if you want to use the fixture as a named parameter, don't do this.

这篇关于pytest-&gt;如何在类下的测试方法中使用夹具返回值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆