2016-06-11 113 views
4

我有一个返回这样的值夹具:pytest - >如何测试方法使用固定装置的返回值类下

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' 

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

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

EDIT 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文件说。

另请在回答中解释什么是最好的方式来使用,而不是产量驱动程序实例。

编辑2:

在这个例子中没有产量,这将是也运行oneTimeTearDown的最佳方式?我跑的删除步骤的收率

@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 

而且我使用单元测试类试过之后,但是当我使用高清setUpClass(CLS),我是不是能够使用在TEST_方法实例化的对象。所以我不知道如何实现这一点。

我也想提供命令行参数,像在命令行中的浏览器,当我试图单元测试,我不得不写在每一类中的命令行参数。我只想在一个地方提供它们,就像测试套件一样。在这里最明智的帮助我。

我对计算器的一个问题,但没有得到回应。你能看看这个吗? Python unittest passing arguments to parent test class

感谢

感谢

回答

2

有使用是在py.text unittest integration documentation概括了一种技术,可以对您有所帮助...内置request夹具。否则,我不知道如何在不提供指定灯具作为方法参数的情况下访问灯具的返回值。现在

@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属性。

我希望有帮助!


UPDATE

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

这是很难知道没有更多的情况下,但在我看来,或许您可以在同一时间实例化一个ABC对象脱身,你实例化driver ...在oneTimeSetUp夹具中。例如...

@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例如,以下是如何使用一个固定的类定义...

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

我不会对第二个例子特别满意。第三个选项是使另一个与oneTimeSetUp完全分开的yield_fixture或类似的,并返回一个ABC实例,并且驱动程序已经打包。

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

后人注意到pytest夹具只是糖和一点魔力是适当的。如果你觉得困难,你根本不需要使用它们。 pytest很高兴执行vanilla unittest TestCases。


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

这是我脑子里想的......

@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 

...请注意,这不返回(或产量)的驱动程序对象,这意味着它不再将这个灯具作为一个命名参数提供给一个函数/方法是有用的,如果所有的测试用例都被写为类(由你的例子建议),这应该没问题。

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

+0

非常感谢解决方案,我有几个后续问题。 你能编辑你的答案来解释最后一行吗? “如果您不打算在其他测试功能中使用oneTimeSetUp夹具(例如通过命名参数),那么上述代码当然可以进一步简化。” 一个重要的问题: 如果我想在我的TestClassDemo中初始化另一个类的对象,那么我应该在哪里初始化它?我还需要将驱动程序传递给另一个类的对象。请帮助,你的回答非常棒。我真的很努力地完成这个工作很多天 –

+0

TestClassDemo中应该有__init __()来创建另一个类的对象吗?是否可以从__init __()提供驱动程序给该对象,还是只能在测试方法中使用它? –

+0

Hi @SunShine,我刚刚删除了最后一句,因为它构造得不好,也没有什么帮助。为了澄清,我的意思是,如果使用'request'夹具为你工作,**每**测试,那么你不需要使用yield_fixture或返回/产生一个值。 – Marty

相关问题