问答 pytest-调用其他模块代码引发错误了,为什么测试报告却显示执行通过

歪歪歪 · May 05, 2021 · Last by 歪歪歪 replied at May 12, 2021 · 2927 hits

目前在做自动化接口测试,遇到个问题,就是跑用例的模块内报错时,就会判断该用例执行失败,但是一旦该模块调用其他模块后,在其他模块内报错了,就显示用例通过,是因为我 logging 没封装好导致的嘛?

控制台输出如上图,明明报错了,却还是显示了用例通过了。
这是我的封装的 log 类,有什么毛病嘛😭 😭

log_path = os.path.join(os.path.dirname(os.path.dirname(os.path.realpath(__file__))), 'logs')
if not os.path.exists(log_path): 
    os.mkdir(log_path)
class Log:
    """
    log日志类
    """

    def __init__(self):
        self.logname = os.path.join(log_path, '%s.log' % time.strftime('%Y_%m_%d'))
        self.logger = logging.getLogger()
        self.logger.setLevel(logging.DEBUG)
        self.formatter = logging.Formatter('[%(asctime)s]-%(filename)s:%(lineno)d]-%(levelname)s:%(message)s')

    def __console(self, level, message):
        fh = logging.FileHandler(self.logname, 'a', 'utf-8')
        fh.setLevel(logging.DEBUG)
        fh.setFormatter(self.formatter)
        self.logger.addHandler(fh)
        ch = logging.StreamHandler()
        ch.setLevel(logging.INFO)
        ch.setFormatter(self.formatter)
        self.logger.addHandler(ch)
        if level == 'info':
            self.logger.info(message)
        elif level == 'debug':
            self.logger.debug(message + '\n' + traceback.format_exc())
        elif level == 'warning':
            self.logger.warning(message + '\n' + traceback.format_exc())
        elif level == 'error':
            self.logger.error(message + '\n' + traceback.format_exc())
        self.logger.removeHandler(ch)
        self.logger.removeHandler(fh)
        fh.close()

    def debug(self, message):
        self.__console('debug', message)

    def info(self, message):
        self.__console('info', message)

    def warning(self, message):
        self.__console('warning', message)

    def error(self, message):
        self.__console('error', message)
共收到 8 条回复 时间 点赞

但是一旦该模块调用其他模块后,在其他模块内报错了,就显示用例通过

没看懂这一句,把你会失败和成功的两个用例具体代码贴上来?

日志模块只是额外打印日志,一般不会影响成功失败的判定吧。

用例断言通过后,其他导致的错误日志,也是会通过的,我理解跟日志模块本身无关,还是要聚焦用例本身?

测试报告是通过断言 (assert) 判定测试是否通过的,不是通过日志。测试报告不对日志做解析。
问题出在没做好断言,楼上已经给出了正解。

pytest 通过与否的依据是断言。你排查看看的

歪歪歪 #5 · May 11, 2021 Author

打了很多字发现无法附加内容和修改内容,就在评论区回了
先简述下我当前项目把,大概就是 pytest+yaml 的项目,其中 yaml 中有一个含 SQL 语句的字段,该字段大概作用是:在执行中,把该语句执行后查询出来的结果存起来,供给其他地方用。
而这里只支持拿取数据库中单个值,比如:

SELECT `phone` FROM `test`.`users` WHERE `phone` = 'XXXXX'

如果此字段填写 SQL 语句外的字符,如:aaa,在执行中会报错,并且最后断言也是显示失败的。

common\test_Template.py [2021-05-10 23:09:34,485]-logs.py:46]-ERROR:执行sql语句报错:(1064, "You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'aa' at line 1")
Traceback (most recent call last):
  File "C:\Users\86139\PycharmProjects\connector\common\execSql.py", line 85, in exec_sql
    cursor.execute(sql)
  File "C:\Users\86139\PycharmProjects\connector\venv\lib\site-packages\pymysql\cursors.py", line 148, in execute
    result = self._query(query)
  File "C:\Users\86139\PycharmProjects\connector\venv\lib\site-packages\pymysql\cursors.py", line 310, in _query
    conn.query(q)
  File "C:\Users\86139\PycharmProjects\connector\venv\lib\site-packages\pymysql\connections.py", line 548, in query
    self._affected_rows = self._read_query_result(unbuffered=unbuffered)
  File "C:\Users\86139\PycharmProjects\connector\venv\lib\site-packages\pymysql\connections.py", line 775, in _read_query_result
    result.read()
  File "C:\Users\86139\PycharmProjects\connector\venv\lib\site-packages\pymysql\connections.py", line 1156, in read
    first_packet = self.connection._read_packet()
  File "C:\Users\86139\PycharmProjects\connector\venv\lib\site-packages\pymysql\connections.py", line 725, in _read_packet
    packet.raise_for_error()
  File "C:\Users\86139\PycharmProjects\connector\venv\lib\site-packages\pymysql\protocol.py", line 221, in raise_for_error
    err.raise_mysql_exception(self._data)
  File "C:\Users\86139\PycharmProjects\connector\venv\lib\site-packages\pymysql\err.py", line 143, in raise_mysql_exception
    raise errorclass(errno, errval)
pymysql.err.ProgrammingError: (1064, "You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'aa' at line 1")

但是如果此字段填写正确的 SQL 语句,但是查询到的值有多个的情况下,如:

SELECT * FROM `test`.`users` WHERE `phone` LIKE 'XXXXX'

在执行中控制台也会报错,但是断言结果却是通过。


用例执行失败!
用例路径:testcase\其他_测试_01.yaml
用例标题:登录测试
报错信息:
catching classes that do not inherit from BaseException is not allowed
Traceback (most recent call last):
  File "C:\Users\86139\PycharmProjects\connector\common\customVar.py", line 82, in init_sql
    sql_dict.update({keys: eval(sql_value)})
  File "<string>", line 1
    61e9326ec6e748bf67110e30ae8a04a4
           ^
SyntaxError: unexpected EOF while parsing

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "C:\Users\86139\PycharmProjects\connector\common\test_Template.py", line 123, in test_in_theaters
    pre_sql = CustomVar().init_sql(test_content_list['pre_sql'])  # 字典类型
  File "C:\Users\86139\PycharmProjects\connector\common\customVar.py", line 84, in init_sql
    except ExecSql as e:
TypeError: catching classes that do not inherit from BaseException is not allowed

因为我这边在断言前就会先输出好一些测试报告,这里我发现断言前的测试报告都没有输出,怀疑是报错后就没有继续执行了。
但很好奇同样都是报错,一个却能在报错后还能继续断言,并且正常输出测试报告,一个却在报错后没有继续向下输出测试报告,并且没有断言。

后来发现报错但断言通过的用例中,在报错后并没有继续往下执行代码,是不是这个原因导致的没有执行断言而默认成功?
而第一种情况失败了也会继续执行往下执行代码。
最后贴上执行错误的代码:

def init_sql(self, content):
        try:
            sql_dict = {}
            for keys, value in content.items():
                sql_value = ExecSql().exec_sql(value)
                if isinstance(sql_value, dict) and sql_value is not None:
                    sql_dict.update({keys: list(sql_value)[1]})
                if isinstance(sql_value, str) and sql_value is not None:
                    sql_dict.update({keys: eval(sql_value)})
            return sql_dict
        except ExecSql as e:
            self.log.error('初始化SQL语句失败:{}'.format(e))
try:
  XXXXX
  pre_sql = CustomVar().init_sql(test_content_list['pre_sql'])  # pre_sql就是用例中的SQL语句
  XXXXX
except Exception as e:
            self.log.error("\n\n用例执行失败!\n用例路径:{0}\n用例标题:{1}\n报错信息:\n{2}".format(path_file_list, test_content_list['title'], e))

歪歪歪 回复

所以你执行错误的代码断言在哪?日志抛出的错误 执行 sql 语句报错 你贴的报错这段代码也没有
而且你的日志抛出异常是在 tyr except 语句块中, 日志捕获异常是会继续执行且认为执行成功的

歪歪歪 回复

对测试框架来说,对一个用例的执行判定是这样的逻辑(具体 fail 和 skip 的异常类可能名字不完全一样,但基本原理都是捕获指定类型的异常):
1、没有任何异常抛出——success
2、抛出 AssertError 类型的异常——fail
3、抛出其他类型的异常——error
4、抛出 SkipException 类型的异常——skip

没执行到断言就结束且没有产生异常==没有断言==没有异常==success

PS:你贴的那段错误代码,所有异常都被捕获了,捕获完也只是打个日志,没有继续向外抛出。测试框架是用例的外面一层,你不给他异常,他只能认为没有异常。

歪歪歪 #8 · May 12, 2021 Author

谢谢各位大佬,找到原因了,就是捕获到异常后没有抛出异常给 pytest。
有没有相关的测试群呀,想要多学习学习

歪歪歪 关闭了讨论 02 Jun 09:10
需要 Sign In 后方可回复, 如果你还没有账号请点击这里 Sign Up