問題描述
我有一個夾具,它返回如下值:
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.
然后我有一個測試類,其中我有多個測試方法,它們都希望使用相同的返回值驅動程序來繼續(xù)測試.
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'
我知道我可以將夾具作為參數(shù)傳遞給我想使用它的每個方法,但這不是最好的方法,因為我在每個方法中都需要它并且應該可以將它傳遞給類然后在所有的測試方法中使用它.
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?
編輯 1:
按照建議在 conftest.py 中創(chuàng)建夾具
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 文件中.
另外請在答案中解釋什么是最好的使用方法而不是屈服驅動程序實例.
Also please explain in the answer what is the best way to use instead of yield driver instance.
編輯 2:
對于這個沒有 yield 的示例,運行 oneTimeTearDown 的最佳方法是什么?我在 yield 之后運行了 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_ 方法中實例化的對象.所以我無法弄清楚如何實現(xiàn)這一目標.
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.
我還想從命令行提供命令行參數(shù),例如瀏覽器,當我嘗試 unittest 時,我必須在每個類中編寫命令行參數(shù).我只想在一個地方提供它們,比如一個測試套件.所以conftest在這里幫助了我.
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 將參數(shù)傳遞給父測試類
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.可能對您有幫助的文本 unittest 集成文檔 ...使用內(nèi)置的 request
固定裝置.否則,我不知道在不提供命名夾具作為方法參數(shù)的情況下訪問夾具返回值的方法.
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")
現(xiàn)在您可以在 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
如果沒有更多上下文就很難知道,但在我看來,您可能可以在實例化 driver
的同時實例化 ABC
對象...在 oneTimeSetUp
夾具中.比如……
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.
哪種方式最適合您?不確定.您需要根據(jù)自己的工作來決定.
Which way is best for you? Not sure. You'll need to decide based on what you're working with.
為后代注意 pytest 固定裝置只是糖和一點魔法是正確的.如果您發(fā)現(xiàn)它們很困難,則根本不需要使用它們.pytest 很高興執(zhí)行 vanilla unittest 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.
另外請在答案中解釋什么是最好的使用方法而不是屈服驅動程序實例.
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
...請注意,這不會返回(或產(chǎn)生)驅動程序對象,這意味著將這個夾具作為命名參數(shù)提供給函數(shù)/方法不再有用,如果您的所有測試用例被編寫為類(由您的示例建議).
... 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).
但是,如果您想將夾具用作命名參數(shù),請不要這樣做.
However, if you want to use the fixture as a named parameter, don't do this.
這篇關于pytest->如何在類下的測試方法中使用夾具返回值的文章就介紹到這了,希望我們推薦的答案對大家有所幫助,也希望大家多多支持html5模板網(wǎng)!