代码之家  ›  专栏  ›  技术社区  ›  crystalattice

对于Pytest,为什么单个测试结果不同于运行所有测试?

  •  2
  • crystalattice  · 技术社区  · 6 年前

    使用pytest和python 3.6,我正在为一个项目进行管道模拟。我有不同的阀门校准等测试工作。

    奇怪的是,如果我在一个目录中运行所有测试,所有测试都会通过。如果我尝试运行一个测试类,它就会失败。我尝试添加设置/拆卸方法来将其与其他代码分开,以防它受到其他类的影响。

    这是测试代码( 自由流速度 是组件库, 自由流速度 是方法库):

    class TestGate3TankLevels:
        @classmethod
        def setup_class(cls):
            ffc.tank2.level = 18.0
            fff.change_tank_level(ffc.tank2, ffc.tank2.level)
            fff.gate1_open()
            fff.gate2_open()
            fff.gate3_open()
            fff.gate4_open()
    
        def test_gate3_tank_levels(self):
            assert ffc.gate1.position == 100
            assert ffc.gate1.flow_out == 19542.86939891452
            assert ffc.gate1.press_out == 13.109851301499999
    
            assert ffc.gate2.position == 100
            assert ffc.gate2.flow_out == 19542.86939891452
            assert ffc.gate2.press_out == 6.5549256507499996
    
            assert ffc.gate3.position == 100
            assert ffc.gate3.flow_in == 19542.86939891452
            assert ffc.gate3.press_in == 13.109851301499999
            assert ffc.gate3.flow_out == 19542.86939891452
            assert ffc.gate3.press_out == 13.109851301499999
            assert ffc.gate6.flow_in == 19542.86939891452
            assert ffc.gate6.press_in == 13.109851301499999
    
            assert ffc.gate4.position == 100
            assert ffc.gate4.flow_in == 0.0
            assert ffc.gate4.press_in == 0.0
            assert ffc.gate4.flow_out == 0.0
            assert ffc.gate4.press_out == 0.0
    
        @classmethod
        def teardown_class(cls):
            ffc.tank2.level = 32.0
            fff.change_tank_level(ffc.tank2, ffc.tank2.level)
    

    当自己运行时,我得到以下结果:

    F
    test_fuel_components.py:408 (TestGate3TankLevels.test_gate3_tank_levels)
    19542.86939891452 != 39085.73879782904
    
    Expected :39085.73879782904
    Actual   :19542.86939891452
     <Click to see difference>
    
    self = <VirtualPLC.tests.models.fuel_farm.test_fuel_components.TestGate3TankLevels object at 0x7f9b35289a20>
    
        def test_gate3_tank_levels(self):
            assert ffc.gate1.position == 100
            assert ffc.gate1.flow_out == 19542.86939891452
            assert ffc.gate1.press_out == 13.109851301499999
    
            assert ffc.gate2.position == 100
            assert ffc.gate2.flow_out == 19542.86939891452
            assert ffc.gate2.press_out == 6.5549256507499996
    
            assert ffc.gate3.position == 100
            assert ffc.gate3.flow_in == 19542.86939891452
            assert ffc.gate3.press_in == 13.109851301499999
            assert ffc.gate3.flow_out == 19542.86939891452
            assert ffc.gate3.press_out == 13.109851301499999
    >       assert ffc.gate6.flow_in == 19542.86939891452
    E       assert 39085.73879782904 == 19542.86939891452
    E        +  where 39085.73879782904 = <PipingSystems.valve.valve.Gate object at 0x7f9b3515ce80>.flow_in
    E        +    where <PipingSystems.valve.valve.Gate object at 0x7f9b3515ce80> = ffc.gate6
    
    test_fuel_components.py:423: AssertionError
    

    但是,如果我在test_fuel_components.py文件中运行所有测试,我将通过:

    Testing started at 2:16 PM ...
    /home/cody/PycharmProjects/VirtualPLC/venv/bin/python /home/cody/.local/share/JetBrains/Toolbox/apps/PyCharm-P/ch-0/182.3341.8/helpers/pycharm/_jb_pytest_runner.py --path /home/cody/PycharmProjects/VirtualPLC/tests/models/fuel_farm/test_fuel_components.py
    Launching py.test with arguments /home/cody/PycharmProjects/VirtualPLC/tests/models/fuel_farm/test_fuel_components.py in /home/cody/PycharmProjects/VirtualPLC/tests/models/fuel_farm
    
    ============================= test session starts ==============================
    platform linux -- Python 3.6.3, pytest-3.6.2, py-1.5.3, pluggy-0.6.0
    rootdir: /home/cody/PycharmProjects/VirtualPLC/tests/models/fuel_farm, inifile:collected 20 items
    
    test_fuel_components.py ....................                             [100%]
    
    ========================== 20 passed in 0.16 seconds ===========================
    Process finished with exit code 0
    

    如果我将这个测试类移动到文件中的另一个位置(现在它位于所有其他测试的末尾),它将导致任何后续测试失败,并使其本身失败。

    我不理解一个测试类是如何自己失败的,但是当与其他测试一起运行时,它是可以的。

    编辑 Link to other tests (太长,无法在此处发布)

    2 回复  |  直到 6 年前
        1
  •  2
  •   Matthew Story    6 年前

    所以这里的问题是,当油箱模型 imported ,就像这里的Tank1:

    # Storage tanks
    # Assumes 36 ft tall tank w/ 1 million gallon capacity = 27778 gallons per foot
    # Assumes 16 inch diam transfer piping
    tank1 = tank.Tank("Tank 1", level=36.0, fluid_density=DENSITY, spec_gravity=SPEC_GRAVITY, outlet_diam=16,
                      outlet_slope=0.25)
    tank1.static_tank_press = tank1.level
    tank1.gravity_flow(tank1.pipe_diam, tank1.pipe_slope, tank1.pipe_coeff)
    

    在不了解这个项目应该做什么的情况下,很难对这个设计提出具体的批评,但是这个设计有大量的全球状态,这使得测试非常困难。

    无论现有设计的优缺点如何,如果您希望测试可靠且隔离,您需要在每次测试开始时将每个水箱的状态重置为已知状态。考虑到这里涉及到多少全球国家,你的选择是相当有限的。

    我的建议是,当您在全局存储了这么多状态时,在每次测试后,使用 setUp tearDown 方法。

    这是未经测试的,但您正在寻找类似的内容:

    original_states = {}
    tanks = [tank1, tank2, tank3, tank4, tank5, tank6]
    tank_attrs = [ "name", "level", "fluid_density", "spec_grav",
                   "tank_press", "flow_out", "pipe_diam", "pipe_slope" ]
    def setUp(self):
        for tank in self.tanks:
            self.original_states[id(tank)] = {}
            for attr in self.tank_attrs:
                self.original_states[id(tank)] = getattr(tank, attr)
    
    def tearDown(self):
        try:
            for tank in self.tanks:
                for attr, value in self.original_states[id(tank)].items():
                    setattr(tank, attr, value)
        finally:
            self.original_states = {}
    

    它基本上在每次测试之前存储原始状态,然后在每次测试之后恢复它。这些属性中有一些神奇之处,因此可能需要一点尝试和错误才能使其100%正常工作。

        2
  •  0
  •   crystalattice    6 年前

    问题出在储油罐的全球状况。一开始我做了一些测试,改变了其中一个坦克的水平,但没有恢复到正常状态。

    通过在开始其余测试之前添加一些函数调用,并确保油箱液位为“满”,它修复了所有问题:

        fff.change_tank_level(ffc.tank1, 36)
        fff.change_tank_level(ffc.tank2, 36)
    

    其中36是满油箱。

    所以,当我进入testgate3tanklevels类时,我更改了水箱的水位,它可以正常工作。然后,Teardown方法将油箱液位恢复正常。