Python Playwright 如何保持登录状态
在编写UI自动化测试用例的时候,通常会采用每个测试用例前打开新页面重新进行登录,以减少用例间的影响,比如一个测试用例执行失败会影响到下一个测试用例的执行,或者下一个用例的开始依赖于上一个用例的结束页面。但是这种方式会使得测试用例的执行时间大幅度上升,尤其是在测试用例划分的颗粒度比较小的时候;加入一个项目中有2000个测试用例,登录操作耗时2秒,那么光耗费在登录上面的时间就有4000秒,达到一个多小时了,严重影响测试执行效率,再假如项目中使用了验证码限制登录的情况,那么就更复杂了。所以,如果可以将登录状态保持住,开始测试用例的时候打开新页面,跳过登录直接进入到待测系统中,就可以大幅度提高测试执行效率。通常,每种UI自动化测试工具都会有类似的功能,这里以Playwright为例来介绍如何实现。
功能实现
在Playwright中提供了现成的方法,通过 context.storage_state(path='<文件路径>') ,可以将当前浏览器上下文的全部状态保存下来,在创建浏览器上下文时,添加 storage_state 参数即可读取保存的文件,从而完全恢复之前的浏览器状态。示例代码如下
# 首次登陆系统 from playwright.sync_api import sync_playwright with sync_playwright() as playwright: browser = playwright.chromium.launch() context = browser.new_context() page = context.new_page() # 登陆系统 page.goto('<login url>') page.fill('<username>', '<username selector>') page.fill('<password>', '<password selector>') page.click('<login button selector>') # 判断是否登陆成功 assert 'Welcome' in page.title() # 保存状态文件 context.storage_state(path='login_data.json')
# 使用已保存的状态文件跳过登录状态直接访问系统 with sync_playwright() as playwright: browser = playwright.chromium.launch() # 创建浏览器上下文时加载状态文件 context = browser.new_context(storage_state='login_data.json') page = context.new_page() # 直接访问登录后的URL page.goto('<welcome url>') # 判断是否访问到登录后的页面 assert 'Welcome' in page.title()
结合Pytest
通过以上代码验证了这种实现方式的可用性,还是很好用的。结合Pytest测试框架,可以通过fixture的形式提供一个已登录的page对象,可以直接在测试用例中使用,实现方式如下:
@pytest.fixture() def logged_page(): ss_file = 'login_data.json' with sync_playwright() as playwright: browser = playwright.chromium.launch() # 判断是否存在状态文件,有的话就加载 if os.path.isfile(ss_file): context = browser.new_context(storage_state=ss_file) else: context = browser.new_context() page = context.new_page() # 直接跳转至登录后页面,前提是未登录用户访问待测系统会自动跳转至登录页面,如果你的系统逻辑不一样,需要修改 page.goto('<welcome url>') # 通过title判断是否成功进入系统,如果没有需要进行登录,一般在第一次访问系统,或登录信息过期等原因会触发 if 'Welcome' not in page.title(): page.fill('<username>', '<username selector>') page.fill('<password>', '<password selector>') page.click('<login button selector>') yield page # 测试执行结束后保存状态文件,前提是测试用例中不能退出系统,安全起见加上异常处理 try: context.storage_state(path=ss_file) except Exception as e: print(e)
结合Clent-Page Object模式
如前,结合Pytest已经可以实现一个很好用的fixture,在很多场景下已经够用了,不过我在项目中结合Clent-Page Object模式进行了另一种实现,核心代码如下:
class Client(ABC): playwright = None browser = None def __init__(self, url: str, *, storage_state_name: str = None): self.url = url self.context = None self.main_page = None self.storage_state_file_path = None if storage_state_name is not None: self.storage_state_file_path = os.path.join('storage_state', f'{storage_state_name}.json') @abstractmethod def register_page(self): pass @abstractmethod def login(self, **kwargs): pass @abstractmethod def is_logged(self): pass def start(self) -> None: Client.playwright = sync_playwright().start() Client.browser = Client.playwright.chromium.launch(**BROWSER_CONFIG) if self.storage_state_file_path is not None and os.path.isfile(self.storage_state_file_path): self.context = Client.browser.new_context(**CONTEXT_CONFIG, storage_state=self.storage_state_file_path) else: self.context = Client.browser.new_context(**CONTEXT_CONFIG) self.main_page = self.context.new_page() self.main_page.goto(self.url) self.register_page() def close(self) -> None: if self.storage_state_file_path is not None: if not os.path.exists('storage_state'): os.mkdir('storage_state') self.context.storage_state(path=self.storage_state_file_path) self.main_page.close() self.context.close() def logged_user(client, url, *, scope = 'function', storage_state_name = None, **kwargs): @pytest.fixture(scope=scope) def user_fixture(): user = client(url, storage_state_name=storage_state_name) user.start() logger.info(f'用户登录: {kwargs}') if not user.is_logged(): user.login(**kwargs) yield user user.close()
继承Client类,使用 logger_user 函数来生成不同终端用户的fixture,以实现继承Pytest。
关于Playwright中如何保持登录状态的文章就介绍至此,更多相关Playwright保持登录状态内容请搜索编程宝库以前的文章,希望以后支持编程宝库!
最近组内推行Playwright进行自动化测试,由我封装了一个简单的框架供大家使用。本意是想让大家使用Page Object模式来编写自动化代码的,可是不知道是因为大家嫌麻烦,还是Playw ...