怎实际web自动化项目中driver对象单例?

测试用例代码如下

import pytest
from page.add_member import AddMember
from page.index import IndexPage


class TestAddMember:

    def setup_class(self):
        self.index = IndexPage(reuse=True)
        self.add_member=AddMember(reuse=True)
    def test_add_member(self):
        add_member = self.index.goto_add_member()
        add_member.add_member()
        assert "test" in add_member.get_name()

如上脚本中AddMember、IndexPage和两个类都是继承自BasePage这个类(和老师上讲的时候的代码完全一致),之前有个贴子问过老师,实际项目中使用debug模式的复用浏览器技术情况多不,有同学说实际项目中不多,老师也同意了这个说法。

一:如果这里BasePage类里不使用浏览器复用,每个用例都会实例化一个driver(甚至不止一次一个,比如上面的代码,调用self.index.goto_add_member()实例化一个driver、 add_member.add_member()有实例化了一个driver),第一个实例化的driver里页面已经到了添加成员,调用add_member.add_member()时,期望的是,在添加成员页面填写数据了,但是他是重新实例化的,并不在添加成员的页面,所以用例执行失败:

二:试过BasePage类写成单例模式,如果用例中只会使用到一个page类,用例可以成功执行,但是,如果用例中涉及到多个page,就会出现多个driver实例,用例还是会执行失败,因为AddMember、IndexPage只是继承BasePage,他们也会分别实例化不同的两个对象

三:如果在每个page类甚至是方法中重新base_url,可以避免一个测试用例不会实例化多个page类,但是这样又不符合PO设计原理

四:实际工作中,或者说成熟的web自动化项目,是一个项目使用一个driver吗?个人观点:我觉得一个项目中使用一个driver的优点:①执行时间大大减少;②更符合实际场景

期望老师解答:
1、答疑下上述四点
2、怎么实现一个项目使用一个driver
3、老师能提供下完整的一个web自动化项目的源码吗,课程中的源码太简略了,只是一个demo,和实际工作中的项目差距太大

回答:

  • 1.正常情况的话driver是会被传递的,也就是说在setup_class里创建了indexpage之后你就启动了一个driver,然后执行到self.index.goto_add_member()的时候这个方法里会创建一个AddMember对象、传入indexpage的这个driver、并且将这个对象return回来支持链式调用或者进行之后的操作,这样连续的操作就不会生成多个driver,比如老师github上代码中是这样写goto方法的,注意到return中创建了新的page实例并且将原有的driver传入这样就不会增加新的driver了
    def goto_login(self):
        self.find((By.LINK_TEXT, "企业登录")).click()
        return Login(self._driver)

老师讲的第三课的实战里,是把driver放在BasePage中的,并且不会向外提供driver
https://github.com/yuruotong1/lagou-1/tree/master/selenium_4

这是老师的第三实战的源码,可以看只有BasePage类里有driver,其他的page类里是不会调用dirver的,并且上课的时候老师也说过,BasePage类的driver不对外提供,既然不对外提供driver,return Login(self,_driver),就违背了BasePage封装原则。你说的那个应该是之前的课程里将的

你看的这些都是复用浏览器的,但是实际情况复用浏览器的情况很少,driver是不对外提供,但是你的page类都是继承自BasePage的,在类/实例内部使用是很正常的,不然的话每次你新建一个页面的实例都会重新生成一个driver就导致了你说的那个问题。对外是说在case里不会去操作driver 而不是说page也不操作了

1、如果复用浏览器实际情况用的很少,还放在实战的第三节来着重讲,实战三是这一个部分的收官之讲,结果讲的内容结果是实际项目中情况很少的?
2、课程里将的BasePage封装其中一个优点是:如果需要更换底层,只需要更改BasePage这个类,如果还需要传递driver,能实现这个优点吗?

  • 当时使用浏览器复主要是因为用的企业微信的例子,需要登录但是又不能用常规的用户名密码登陆,只能扫二维码,这个地方解决起来比较麻烦,为了不花多的时间去处理登录问题所以用了浏览器复用这种方法来节省时间优先讲主要的部分,这块也并不是讲课的重点,讲课的具体内容还是一个整体的设计思路,为了把功能实现和业务逻辑进行拆分。
  • 而且我觉得PO模式是一种思想和思路,并不是说非要100%照搬,还是要考虑到实际情况和实际问题。最终还是为了减少维护成本,提高效率嘛。
  1. 复用浏览器不是实际情况用的少,而是当你的代码持续集成至jenkins的时候用的很少,甚至不用,但是这个东西在代码调试的时候用的还是非常非常多的。
  2. 如果有些方法,只在一两处使用了driver,比如switch_to、或者perform。当你的底层更换的时候。这一两处更换起来并不费事,所以这个加不加PO都OK。但是如果比如find_element 这种方法,每一步都在用的,是一定要封装到base_page中。所以要不要传递,要不要封装,都取决你个人的写法。

我看你一直在纠结这个问题,最后再补充一下, 如果我有一艘船,在水路上面走可以节省效率,在陆地上面用就是人拉船,非常费时费力。设计模式也是这么一个东西,在实际工作中,要找对切入点使用。哪些地方该封装,哪些地方不用封装,你多写几个项目多重构几次就感受到了。

你这个问题解决了吗?我看视频回放也是出现多个dirver的现象,感觉你提的问题很有针对性