首页 > 解决方案 > 如何在python中获取测试方法的开始行号和结束行号?

问题描述

我目前正在尝试获取 python 文件中所有测试方法的第一行和最后一行编号。

例如:

文件 test_lift.py 测试文件 lift.py。

test_lift.py

1 import random
2
3 from src.lift import Lift
4 from flaky import flaky
5
6
7 def test_upwards():
8         tester = Lift()
9         tester.upwards()
10        assert 1 == tester.curr_floor
11
12 def test_downwards():
13        tester = Lift()
14        tester.curr_floor = 1
15        tester.downwards()
16        assert 0 == tester.curr_floor
17        tester.downwards()
18        assert 0 == tester.curr_floor
19
...

我现在想获取 test_lift.py 中每个测试方法的第一行和最后一行的编号,例如:

测试向上, 7, 10

test_downwards, 12, 18

我已经尝试过使用 conftest.py,但没有任何成功。也许我忽略了什么?解决方案不一定必须在 python 中。如果有人知道如何通过解析文件来解决这个问题,我很好。

标签: pythonpytest

解决方案


或者,没有任何额外的模块(但有一些 Python 内部):

>>> def thing():
...  a = 5
...  b = a + 4
...  return a + b * 2
... 
>>> thing.__code__.co_firstlineno  # self-explanatory
1
>>> list(thing.__code__.co_lnotab)
[0, 1, 4, 1, 8, 1]
>>> thing.__code__.co_firstlineno + sum(line_increment for i, line_increment in enumerate(thing.__code__.co_lnotab) if i % 2)
4

所以你有了它:函数从第 1 行 ( thing.__code__.co_firstlineno) 到第 4 行。

dis模块证明了这一点(第一列中的数字是行号):

>>> import dis
>>> dis.dis(thing)
  2           0 LOAD_CONST               1 (5)
              2 STORE_FAST               0 (a)

  3           4 LOAD_FAST                0 (a)
              6 LOAD_CONST               2 (4)
              8 BINARY_ADD
             10 STORE_FAST               1 (b)

  4          12 LOAD_FAST                0 (a)
             14 LOAD_FAST                1 (b)
             16 LOAD_CONST               3 (2)
             18 BINARY_MULTIPLY
             20 BINARY_ADD
             22 RETURN_VALUE

注意最后一个数字是 4 - 这是函数最后一行的数字。

更多关于结构的信息co_lnotab可以在这里这里找到。


测试程序

def span_of_function(func):
  start = func.__code__.co_firstlineno
  end = start + sum(line_increment for i, line_increment in enumerate(func.__code__.co_lnotab) if i % 2)
  
  return start, end

def hello(name):
  print(f'Hello, {name}!')
  return 5

print(span_of_function(span_of_function))
print(span_of_function(hello))

输出:

$ python3 test.py
(1, 5)
(7, 9)

推荐阅读