13

One of my attributes is a property where the setter calls a validation function that raises an exception if the new value is invalid:

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

I'm trying to add a test to ensure that this fails. However, I can't figure out how to get assertRaises to work with an assignment.

The normal syntax of assertRaises requires a method, not an attribute/property:

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

The other forms I've tried are invalid 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

How do I test failure of assignment to a property?

Note: Python 2.6, I know unittest has some new features in 2.7

Lenna
  • 1,445
  • 9
  • 21

2 Answers2

17

When you want to use unittest to test that an exception occurs in a block of code rather than just a function call, you can use assertRaises as a context manager:

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

This use can be found in the unittest docs.

While this is not available in Python 2.6, and won't work for you as such (I just saw your note), I think it's worth including among the answers, as it's probably the clearer way to do this for python 2.7+.

Wilduck
  • 13,822
  • 10
  • 58
  • 90
8

Before Python 2.7, you want to use setattr(object, name, value) (doc). This allows you to set a value to an attribute.

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

This should always work, because if the attribute is a property and thus "secretly" calls a function, it must be within a class. I don't think a standard assignment can fail (although an expression on the right side can fail, i.e. x = 1/0).

Lenna
  • 1,445
  • 9
  • 21
  • 1
    Assignment can fail for a variety of reasons (say, adding an attribute which isn't in `__slots__`), even if you don't have a descriptor, but this is the correct answer otherwise. – Julian Aug 17 '12 at 16:41