Тестирование сбоя задания с помощью unittest

Один из моих атрибутов - это свойство, когда сеттер вызывает функцию проверки, которая вызывает исключение, если новое значение недействительно:

pos.offset = 0
# @offset.setter calls validate(offset=0)
# PositionError: Offset may not be 0.

Я пытаюсь добавить тест, чтобы убедиться, что это не удается. Однако я не могу понять, как заставить assertRaises работать с заданием.

Нормальный синтаксис assertRaises требует метода, а не атрибута/свойства:

self.assertRaises(PositionError, pos.offset, 0)
# TypeError: 'int' object is not callable

Другие формы, которые я пробовал, являются недопустимыми Python:

self.assertRaises(PositionError, pos.offset = 0)
# SyntaxError: Keyword can't be an expression
self.assertRaises(PositionError, lambda: pos.offset = 0)
# SyntaxError: lambda cannot contain assignment

Как проверить неудачу назначения свойства?

Примечание: Python 2.6, я знаю, что unittest имеет некоторые новые функции в 2.7

Ответ 1

Если вы хотите использовать unittest для проверки того, что исключение происходит в блоке кода, а не только вызове функции, вы можете использовать assertRaises в качестве менеджера контекста:

with self.assertRaises(PositionError):
    pos.offset = 0

Это использование можно найти в unittest docs.

Хотя это не доступно в Python 2.6 и не будет работать для вас как такового (я только что видел вашу заметку), я думаю, что это стоит включить в ответы, так как это, вероятно, более ясный способ сделать это для python 2.7 +.

Ответ 2

До Python 2.7, вы хотите использовать setattr(object, name, value) (doc). Это позволяет установить значение для атрибута.

self.assertRaises(PositionError, setattr, pos, "offset", 0)
# ... ok

Это всегда должно работать, потому что, если атрибут является свойством и, таким образом, "тайно" вызывает функцию, он должен находиться внутри класса. Я не думаю, что стандартное назначение может завершиться неудачно (хотя выражение с правой стороны может выйти из строя, т.е. x = 1/0).