Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Testing failure of an assignment with unittest

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

like image 603
Lenna Avatar asked Aug 17 '12 16:08

Lenna


People also ask

How do you write a unit test exception in Python?

There are two ways you can use assertRaises: using keyword arguments. Just pass the exception, the callable function and the parameters of the callable function as keyword arguments that will elicit the exception. Make a function call that should raise the exception with a context.

Which function in unittest will run all of your tests?

pytest. The pytest test runner supports the execution of unittest test cases.

How do you test a function that does not return anything?

If a method is not returning anything through the "return" statement (void method), it may return data through its arguments. In this case, you can test the data returned in any argument. Else if a method is not returning any data through its arguments, it may change values of its instance variables.

What does unittest main () do?

Internally, unittest. main() is using a few tricks to figure out the name of the module (source file) that contains the call to main() . It then imports this modules, examines it, gets a list of all classes and functions which could be tests (according the configuration) and then creates a test case for each of them.


2 Answers

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+.

like image 110
Wilduck Avatar answered Oct 12 '22 11:10

Wilduck


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).

like image 42
Lenna Avatar answered Oct 12 '22 10:10

Lenna