#python-3.x #python-unittest
#python-3.x #python-unittest
Вопрос:
Я запускаю некоторые модульные тесты из командной строки python -m unittest
.
Из-за именования моих модульных тестов модульный тест, который тестирует метод класса, запускается первым.
Затем это приведет к сбою других тестов без всякой причины. Все тесты, которые завершаются неудачей, должны вызывать ошибку, но все они терпят неудачу, утверждая, что ошибка никогда не возникала. Когда эти тесты отлаживаются в IDE, ошибка выдается правильно. Кроме того, когда эти тесты выполняются по отдельности, они проходят.
Когда я полностью удаляю функции, которые проверяют методы класса, из тестов. Все тесты проходят без проблем в командной строке.
Кто-нибудь может предложить объяснение, почему это происходит, и что я могу сделать, чтобы это исправить? Ниже приведен MWE с выводом теста:
Код
import unittest
class MyClass:
def __init__(self):
self._my_val = None
@classmethod
def from_dict(cls, dict_):
cls.my_val = dict_['my_val']
@property
def my_val(self):
return self._my_val
@my_val.setter
def my_val(self, value):
if value == 5:
raise ValueError
self._my_val = value
class Tests(unittest.TestCase):
def test_classmethod(self):
MyClass.from_dict({
'my_val': 1
})
def test_my_val_raise_error(self):
m = MyClass()
with self.assertRaises(ValueError):
m.my_val = 5
def test_my_val_no_error(self):
m = MyClass()
m.my_val = 4
self.assertEqual(m.my_val, 4)
if __name__ == '__main__':
unittest.main()
Вывод
"C:Program FilesPython39python.exe" C:/Users/user/AppData/Roaming/JetBrains/PyCharmCE2020.3/scratches/scratch.py
..F
======================================================================
FAIL: test_my_val_raise_error (__main__.Tests)
----------------------------------------------------------------------
Traceback (most recent call last):
File "C:UsersuserAppDataRoamingJetBrainsPyCharmCE2020.3scratchesscratch.py", line 31, in test_my_val_raise_error
m.my_val = 5
AssertionError: ValueError not raised
----------------------------------------------------------------------
Ran 3 tests in 0.001s
FAILED (failures=1)
Process finished with exit code 1
Комментарии:
1. Не должно иметь значения, в каком порядке выполняются ваши тесты — это говорит о том, что вы не в состоянии правильно очистить изменения состояния. Разве этот метод класса не должен создавать новый экземпляр, а не изменять состояние самого класса?
2. Я думаю, что создание нового экземпляра вызывает ту же проблему. Я пойду и проверю сейчас.
Ответ №1:
Здесь происходит то, что у вашего класса есть свойство с именем my_val
. Но ваш from_dict
метод класса переопределяет его и my_val
становится обычным атрибутом (больше не свойством).
Это продемонстрировано в приведенном ниже коде.
Свойства могут быть сложными, вы можете прочитать этот блог, который я написал на эту тему здесь.
class MyClass:
def __init__(self):
self._my_val = None
@classmethod
def from_dict(cls, dict_):
cls.my_val = dict_['my_val']
@property
def my_val(self):
return self._my_val
@my_val.setter
def my_val(self, value):
if value == 5:
raise ValueError
self._my_val = value
# before override
print(MyClass.my_val) # --> <property object at 0x7f9725423950>
# override
MyClass.from_dict({'my_val': 1})
# after override
print(MyClass.my_val) # --> 1
print(type(MyClass.my_val)) # --> <class 'int'>
Комментарии:
1. Чтобы продолжить это, правильный способ инициализации вашего метода classmethod будет следующим. Создание временного экземпляра класса (
myclass = cls()
), за которым следует предпочтительное назначение (myclass.my_val = dict_['my_val']
) и, наконец, возврат экземпляра класса (return myclass
) .2. Да, я понял это, когда увидел в окне структуры в PyCharm, в моем классе было несколько дополнительных полей. Я изменил метод класса, и теперь все работает отлично. 🙂