测试人社区

【python章节7】数据驱动PO讲解,有个关于死循环的问题

直接上代码:

# 捕获定位元素的异常
except Exception as e:
    self._error_cont += 1
    if self._error_cont >= self._error_max:
        raise e
    # 从黑名单中持续取出各类弹窗
    # 这里存在一个问题,如果弹窗都没有在黑名单中,那么下面的的find方法会继续查找
    for black in self._black_list:
        # 判断弹窗是否在页面中
        elements = self._driver.find_elements(*black)
        # 如果在,那么长度会大于0
        if len(elements) > 0:
            # 对第一个找到的页面进行点击
            elements[0].click()
            # 然后再次定位需要的元素
           !!# return self.find(by, locator)
    raise e

这段代码中,按我个人的理解,最后的return语句,是在条件满足定位到任意元素的时候发生的,那么如果我在整个循环中都定位不到元素,这一项就不会发生,会直接跳出循环,执行raise终止程序,这里的死循环并不会发生。

这里是不是可以改成下面的代码:

for black in self._black_list:
        # 判断弹窗是否在页面中
        elements = self._driver.find_elements(*black)
        # 如果在,那么长度会大于0
        if len(elements) > 0:
            # 对第一个找到的页面进行点击
                      for element in elements:
                elements[0].click()
            # 然后再次定位需要的元素
            return self.find(by, locator)

想请老师解答一下这样修改是否可行,或是纠正一下我的错误

我的理解是这样的

  • 老师的代码中,定义了最大错误次数和计数,这样避免一种情况:如果找到了一个黑名单里的元素 但是click操作并没有能够将这个黑名单问题解决掉,导致再次定位的时候又进入了相同的循环,这样陷入了死循环中
  • 你的代码中首先有一个问题就是这段内容不管elements中找到了几个元素 你只是循环点击了第一个元素好几次。。
  • 你这个思路我感觉想解决的是:“查找到了黑名单元素但是定位出来的元素有好几个,真正的那个黑名单元素不是第一个。”这种问题,不知道我理解的对不对,但是我觉得这样也会导致一个问题,可能会在黑名单处理期间多点击了好几个类似元素,可能会导致运行结果不是想要的结果。。
  • 我个人觉得还是没有定位到的话就报错比较好,这样你就可以在调试期间修改你的黑名单定位,能够更准确的定位到异常并进行处理,防止正式跑的时候出问题~

首先感谢解答。
我大概明白了,老师视频里说的死循环意思是定位到了元素,但点击无法解决,那么意味着这次程序就终止了,需要另外的行为操作来解决这样的元素对吧。

另外更正一个错误,我的代码上传的时候复制的格式有问题,应该如下:

for black in self._black_list:
        # 判断弹窗是否在页面中
        elements = self._driver.find_elements(*black)
        # 如果在,那么长度会大于0
        if len(elements) > 0:
            # 对第一个找到的页面进行点击
                      for element in elements:
                           element.click()
            # 然后再次定位需要的元素
            return self.find(by, locator)

这样循环点击的话,其实我觉得逻辑还是一样的,在有限的重试次数下并不会造成死循环。
其实在这里,我的重点是吧return放在了外面

我一直认为
elements = self._driver.find_elements(*black)
这里之所以用find_elements而不用find_element,只是因为找不到元素时不会报错而是返回空列表以执行接下来的语句 :stuck_out_tongue:
在一个页面,对于同一个black,存在多个的情况应该很少很少吧~

对于同一个页面,出现多个相同的black的情况

if len(elements) > 0:
    # 对第一个找到的页面进行点击
    for element in elements:
        element.click()
    return self.find(by, locator)

我觉得你的写法应该是没有问题,老师的写法只是把这种情况处理放到了return self.find(by, locator)再一次尝试查找元素后对黑名单判断再处理黑名单弹窗

在这一层for black in self._black_list:循环结束后,如果没有raise e那么报错信息就丢失了,实际self.find(by, locator)的功能也没有实现,我觉得这一行不应该去掉

error_count += 1 
    if error_count == self.error_max:
        raise e

这里处理的死循环应该是找了self.error_max次该元素没有找到并且已经处理了self.error_max-1次弹窗,就直接报错不再递归调用吧

其他还有什么会死循环的情况吗?是我没考虑到什么情况吗 :thinking:

  • return放在里面的话 就是按照黑名单中的元素定位进行循环查找(for black in self._black_list),某个定位查到结果(if len(elements) > 0)后默认结果列表的第一个就是黑名单中的元素然后进行点击(elements[0].click()),点击之后默认异常处理完成然后回到正常的测试流程中再次点击之前要定位的元素(return self.find(by, locator))
  • return放在外面的话 前面的逻辑也是一样的 按照黑名单中的元素定位进行循环查找(for black in self._black_list) 某个定位查到结果(if len(elements) > 0)后 循环点击所有找到的结果而不是默认第一个结果就是黑名单中的元素(element.click()),都点击之后再回到正常的测试流程中再次点击之前要定位的元素(return self.find(by, locator))
  • 其实区别就在于是否默认黑名单元素为找到结果的第一个(或者说唯一一个)
  • 还有一种可能 我感觉你是不是理解为(self._driver.find_elements(*black)) 找回的是所有可能的黑名单元素?然后你想循环点击把各种找到的黑名单元素都处理掉这样就不用每次都找一遍正常元素再找一遍黑名单了 但是不是这样的 因为前面的(for black in self._black_list)已经是取出黑名单中的一条来查找了,所以一次只能处理一条黑名单在这个地方已经确定下来了。