• 自动化测试的方向 at November 27, 2020

    想问您一个问题,UI 自动化和 app 自动化的界限在哪里呢,app 自动化算不算 UI 自动化呢

  • 1.问的两个场景,一个用例执行前进行的处理,一个是用例执行后进行的处理。

    2.场景:在每个用例发生前,我需要检查一下 url 是否为正确的,如果是,则直接进入用例,如果不是,则需要将将页面进入设定的 url,那么这个情况下,每个用例都有自己的 url,但是,如果每个用例去写一遍 if……else,对于代码的复用以及维护就不太方便了,如果之后这个逻辑变了需要每个用例去删除,如果用装饰器,我觉得也差不多,需要一个一个删,但是如果装饰器 +BaseCasesetup,之后每个用例继承这个 Base Case,那么也继承了 setup,是否可行呢,但是也存在 url 无法传到BaseCase情况吧,这个场景该如何使用BaseCase呢,或者该如何实现呢?

    3.这两天一直在读 HTMLRunner 代码,看懂了您发的实例,确实感觉有一定的实用性,在想 def startTest(self, test) 可否完成 2 中的场景?

  • 您好,网上用例基类的信息非常少,对于它的使用我仍然存在疑惑但是无法找到答案:

    1

    如果我想要对每个用例出错时进行处理,比如截图,记录日志之类的,是否可以不对每个 test case 进行处理,而是在BaseCase里面处理就可以呢?

    目前我想到的是,使用函数装饰器,在每个用例前加上@decorator_name,装饰器如下:

    def decorator_name(url):
        def decorator(fun):
            @wraps(fun)
            def wrapped_function(self, *args, **kwargs):
                # 传入url,做判断
                if self.driver.current_url != url:
                    self.driver.get(url)
                try:
                    fun(self, *args, **kwargs)
                except:
                    # 如果用例发生了问题,则进行一些错误处理
                    raise
            return wrapped_function
        return decorator
    

    这些操作每个用例是相同的,所以没必要每个用例都写一遍,但是装饰器有时候也会容易忘记,是否可以通过BaseCase解决这个问题呢?

    2

    或者在每个用例类中都有一个专门的变量 x,但是在进入用例前,我需要对 x 进行一些判断,比如 x 是否大于 1,这个肯定是需要一个装饰器传入参数的,我想过在BaseCase上将这个装饰器装饰到 setup 上,但是如何把值传过来呢?在这个场景中,是否可以用用例基类呢?

  • 有修改函数名称,但是 ascii 会先考虑文件名,然后是 class 名,然后是函数名

  • 确实不是技术含量很高的问题,但是是我纠结的一个点,我觉得确实上图中的命名不好看也不规范

  • 1.已经设置了 logger 的 handler。原因是报告使用io.StringIO 并进行了 stdout 和 stderr 的重定向,所以我必须也在项目中重定向到报告中的重定向的 stdout 和 stderr,这样的话涉及到改了一部分报告源代码。
    2.关于报告,使用的是unitestreport ,这应该是比较常见的操作。

  • 谢谢,我看看
    1.优化 po 框架:basepage。basecase。页面元素和页面功能分开,页面数据和代码分开(实现数据驱动)
    2.可以看一下 unittestreport 项目的源代码(在 github 上开源)可以学到很多东西,里面包括但不限于输出流,traceback,前端 js,装饰器
    3.python logging(包括回滚日志)装饰器(优雅的写代码)

  • 谢谢,我尝试一下!

  • 暂时不打算用 pytest

  • 其实 也是在想能不能优化 html 报告,将里面的错误信息改一改,加错误截图之类的。有没有方法呢?想了两天了,也看了很久的代码,但是没什么思路

  • 今天拜访了一个程序员网址 LearnKu,从中得到了一些提示,新用户入驻,首先是注册,邮箱激活,这些都是比较容易完成的,然后是发帖,发帖之前必须完成一些关于发帖文明的题目,比如以下哪些做法是正确的?有点像 b 站发弹幕之前必须通过的那几十道题目,我觉得还是可以设置一个这样的发帖之前必须通过的测试题的,不过也有缺点,一个是做题比较麻烦,不是所有人有耐心做完,可能会影响网站新入驻用户数目,另外就是题目设置库,如果就那固定的 20 道题,他们做一道就把答案记下来了还是不行,可以题库设置很多道,但是随机抽取其中多少道,每个人的题都不一样的。

  • 怎么说呢?
    1.这是上面安排的任务。
    2.公司真的不知道 UI 自动化投资回报率低吗,但是短期内确实大势所趋
    3.本项目软件生命周期长,需求较稳定,是合适的,不是无用功,也确实遇到了如题目所示的问题
    的确正在学习中,没办法像您一样考虑地那么长远,但是尝试 ui 自动化,把结果告诉他们到底行不行是我的工作。

  • 我也这么觉得,但是我觉得如果传入的元素,也有不太好的地方,可能有 staleElementsReferenceException 异常,所以我采用的办法是更新 get_element.(多传入一个参数 n:第几个元素)把这个函数变成 find_elements 然后 element[n],默认为 0,这样也不会有 noexception 异常啦

  • 我们公司也只有我一个。
    我觉得自动化测试不能替代所有的手动测试吧,它只是在产品迭代的时候验证一下之前的功能是否正确,甚至最好测一些基本不变的功能,减少人工的工作量。在所有的 bug 中,自动化测试只能测出最多五分之一,但是它的存在,可以在产品每次增加新功能时,手工测试的小伙伴更多的关注新功能时,保证老的功能没问题。
    另外,测试需求很重要,你需要测什么,如果有产品需要测,就做自动化,如果有协同测试或者别的需求,也可以写一些测试工具或者平台,这个时候可以去多学一些前后端的知识。
    我也不是很懂,也是在实践中成长,如有说得不对的,请谅解。

  • 我已经知道了,谢谢,不过我觉得还是原生函数放到基础页面层比较好。

  • 是这样的,为什么这个跳转链接有测试需求是因为我要测试的 app 和 web 一起的,当我在 web 上新增了一个 xx,里面会要填写其跳转链接,这时我去 app 上面验证,这个跳转链接是否与我当时新增时一致,所以我需要获取到 url,这个链接是 web 端我测试的时候自己获取的,不会写死,这个功能就是希望去验证这个东西。

  • 搞这么复杂是想要验证是否打开的链接是正确的

  • 好的,谢谢你耐心解答我的疑惑。我也学到了用例基类这个方法,虽然我不是接口测试,只是 web UI 测试,但是感觉还是很好用的

  • 二次封装 selenium 的方法,做到页面与业务分离。

  • 传入 element,是直接传入 find_element 的结果,这样做后期维护会有问题吗

  • 这样做不是看起来奇不奇怪的问题,而是这样做到时候日志里面显示日志所在行和所在文件会是固定的,都是 BaseCase 这一行。所以我放弃了这个方式。

  • 确实不改变,我也尝试了你说的方式,感觉用例基类的方式也是不改变的:

    class BaseCase(unittest.TestCase):
    
        @classmethod
        def setUpClass(cls) -> None:
            # 获取当前时间
            now = timer.current_time("%Y_%m_%d")
            filename = dir_config.logs_dir + r"\{}.log".format(now)
            # 格式
            # %(asctime)s 打印日志时间 %(filename)s: 打印当前执行程序名
            # %(lineno)d: 打印日志的当前行号 %(levelname)s: 打印日志级别名称 %(message)s: 打印日志信息
            fmt = "%(asctime)s %(filename)s %(funcName)s [line:%(lineno)d ] %(levelname)s %(message)s"
            date_fmt = "%a %d %b %Y %H:%M:%S"
            # 打印到控制台
            stream_handler = logging.StreamHandler()
            stream_handler.setLevel(logging.ERROR)
            # 回滚文件输出
            rotating_handler = RotatingFileHandler(filename, maxBytes=1024 * 1024 * 5, backupCount=10)
            # 设置logging的输入内容形式及输出渠道
            logging.basicConfig(format=fmt,
                                datefmt=date_fmt,
                                level=logging.INFO,
                                handlers=[stream_handler, rotating_handler])
            cls.logger = logging.getLogger(cls.__name__)
    
    
    在其他用例中即使用self.logger.info(...)
    
  • 您好,请问您觉得,像 click ,get_attribute 封装等等,是传入 location 比较合适,还是传入 element 比较合适呢

  • 好像这样子日志的封装能够比较优雅的完成,且行号正确。
    继承 Logger 方法,在里面对 Filter, handler 进行一些赋值

  • class Logger(logging.Logger):
       """日志的封装"""