Hi folks I wasn't sure if this warranted a bug in the tracker, so I thought I'd raise it here first. unittest has assertIn, assertNotIn, assertEqual, assertNotEqual and so on. So, it seems odd to me that there isn't assertNotRaises. Is there any particular motivation for not putting it in? I've attached a simple patch against Python 3's trunk to give an idea of what I have in mind. Thanks Wilfred
Sure, you just *do* it. The only advantage I see in assertNotRaises is that when that exception is raised, you should (and would) get a failure, not an error.
On 27 September 2011 19:59, Laurens Van Houtven <_@lvh.cc> wrote:
Sure, you just *do* it. The only advantage I see in assertNotRaises is that when that exception is raised, you should (and would) get a failure, not an error.
It's a useful distinction. I have found myself writing code of the form: def test_old_exception_no_longer_raised(self): try: do_something(): except OldException: self.assertTrue(False) in order to distinguish between a regression and something new erroring. The limitation of this pattern is that the test failure message is not as good.
On 27/09/2011 19:59, Laurens Van Houtven wrote:
Sure, you just *do* it. The only advantage I see in assertNotRaises is that when that exception is raised, you should (and would) get a failure, not an error. There are some who don't see the distinction between a failure and an error as a useful distinction... I'm becoming more sympathetic to that view.
All the best, Michael
_______________________________________________ Python-Dev mailing list Python-Dev@python.org http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/fuzzyman%40voidspace.org.u...
-- http://www.voidspace.org.uk/ May you do good and not evil May you find forgiveness for yourself and forgive others May you share freely, never taking more than you give. -- the sqlite blessing http://www.sqlite.org/different.html
Oops, I accidentally hit Reply instead of Reply to All...
On Wed, Sep 28, 2011 at 1:05 PM, Michael Foord
On 27/09/2011 19:59, Laurens Van Houtven wrote:
Sure, you just *do* it. The only advantage I see in assertNotRaises is that when that exception is raised, you should (and would) get a failure, not an error.
There are some who don't see the distinction between a failure and an error as a useful distinction... I'm becoming more sympathetic to that view.
I agree. Maybe if there were less failures posing as errors and errors posing as failures, I'd consider taking the distinction seriously. The only use case I've personally encountered is with fuzzy tests. The example that comes to mind is one where we had a fairly complex iterative algorithm for learning things from huge amounts of test data and there were certain criteria (goodness of result, time taken) that had to be satisfied. In that case, "it blew up because someone messed up dependencies" and "it took 3% longer than is allowable" are pretty obviously different... Considering how exotic that use case is, like I said, I'm not really convinced how generally useful it is :) especially since this isn't even a unit test...
All the best,
Michael
cheers lvh
On Tue, Sep 27, 2011 at 07:46:52PM +0100, Wilfred Hughes wrote:
+ def assertNotRaises(self, excClass, callableObj=None, *args, **kwargs): + """Fail if an exception of class excClass is thrown by + callableObj when invoked with arguments args and keyword + arguments kwargs. + + """ + try: + callableObj(*args, **kwargs) + except excClass: + raise self.failureException("%s was raised" % excClass) + +
What if I want to assert my test raises neither OSError nor IOError? Oleg. -- Oleg Broytman http://phdru.name/ phd@phdru.name Programmers don't die, they just GOSUB without RETURN.
Oleg Broytman wrote:
On Tue, Sep 27, 2011 at 07:46:52PM +0100, Wilfred Hughes wrote:
+ def assertNotRaises(self, excClass, callableObj=None, *args, **kwargs): + """Fail if an exception of class excClass is thrown by + callableObj when invoked with arguments args and keyword + arguments kwargs. + + """ + try: + callableObj(*args, **kwargs) + except excClass: + raise self.failureException("%s was raised" % excClass) + +
What if I want to assert my test raises neither OSError nor IOError?
Passing (OSError, IOError) as excClass should do it. But I can't see this being a useful test. As written, exceptions are still treated as errors, except for excClass, which is treated as a test failure. I can't see the use-case for that. assertRaises is useful: "IOError is allowed, but any other exception is a bug." makes perfect sense. assertNotRaises doesn't seem sensible or useful to me: "IOError is a failed test, but any other exception is a bug." What's the point? When would you use that? -- Steven
On Tue, Sep 27, 2011 at 4:43 PM, Steven D'Aprano
But I can't see this being a useful test. As written, exceptions are still treated as errors, except for excClass, which is treated as a test failure. I can't see the use-case for that. assertRaises is useful:
"IOError is allowed, but any other exception is a bug."
makes perfect sense. assertNotRaises doesn't seem sensible or useful to me:
"IOError is a failed test, but any other exception is a bug."
What's the point? When would you use that?
I've run across a few cases where this is the correct behavior. The most recent one that comes to mind is while testing some code which has specific silencing options: specifically, writing a main file and a backup file, where failure to write the backup is not an error, but failure to write the main is. As such, the test suite should have the following tests: - Failure to write the main should assert that the code raises the failure error. No error is a failure, any other error is an error, that error is a success. (it may also check that the backup was written) - Failure to write the backup should assert that the code does not raise the failure error. No error is a success, that error is a failure, any other error is a error. (it may also check that the main was written) - Both succeeding should assert that the files were actually written, and that no error was raised. Any other result is an error. Now, the difference between a Failure and an Error is more or less a mute point, however I would expect an Error to be any unexpected result, while a Failure is a predicted (either via forethought or prior tests) but incorrect result.
On 27 Sep, 11:58 pm, ckaynor@zindagigames.com wrote:
On Tue, Sep 27, 2011 at 4:43 PM, Steven D'Aprano
wrote: But I can't see this being a useful test. As written, exceptions are still treated as errors, except for excClass, which is treated as a test failure. I can't see the use-case for that. assertRaises is useful:
"IOError is allowed, but any other exception is a bug."
makes perfect sense. assertNotRaises doesn't seem sensible or useful to me:
"IOError is a failed test, but any other exception is a bug."
What's the point? When would you use that?
I've run across a few cases where this is the correct behavior. The most recent one that comes to mind is while testing some code which has specific silencing options: specifically, writing a main file and a backup file, where failure to write the backup is not an error, but failure to write the main is. As such, the test suite should have the following tests: - Failure to write the main should assert that the code raises the failure error. No error is a failure, any other error is an error, that error is a success. (it may also check that the backup was written)
This is assertRaises, not assertNotRaises.
- Failure to write the backup should assert that the code does not raise the failure error. No error is a success, that error is a failure, any other error is a error. (it may also check that the main was written)
This is calling the function and asserting something about the result.
- Both succeeding should assert that the files were actually written, and that no error was raised. Any other result is an error.
Now, the difference between a Failure and an Error is more or less a mute point, however I would expect an Error to be any unexpected result, while a Failure is a predicted (either via forethought or prior tests) but incorrect result.
assertNotRaises doesn't make anything possible that isn't possible now. It probably doesn't even make anything easier - but if it does, it's so obscure (and I've read and written thousands of tests for all kinds of libraries over the years) that it doesn't merit a dedicated helper in the unittest library. Jean-Paul
On Sep 27, 2011 5:56 PM,
assertNotRaises doesn't make anything possible that isn't possible now. It
probably doesn't even make anything easier - but if it does, it's so obscure (and I've read and written thousands of tests for all kinds of libraries over the years) that it doesn't merit a dedicated helper in the unittest library.
Jean-Paul
+1 for keeping it simple. TOOWTDI.
On Wed, Sep 28, 2011 at 09:43:13AM +1000, Steven D'Aprano wrote:
Oleg Broytman wrote:
On Tue, Sep 27, 2011 at 07:46:52PM +0100, Wilfred Hughes wrote:
+ def assertNotRaises(self, excClass, callableObj=None, *args, **kwargs): + """Fail if an exception of class excClass is thrown by + callableObj when invoked with arguments args and keyword + arguments kwargs. + + """ + try: + callableObj(*args, **kwargs) + except excClass: + raise self.failureException("%s was raised" % excClass) + +
But I can't see this being a useful test.
Me too. Oleg. -- Oleg Broytman http://phdru.name/ phd@phdru.name Programmers don't die, they just GOSUB without RETURN.
On 9/27/2011 2:46 PM, Wilfred Hughes wrote:
Hi folks
I wasn't sure if this warranted a bug in the tracker, so I thought I'd raise it here first.
unittest has assertIn, assertNotIn, assertEqual, assertNotEqual and so
These all test possible specification conditions and sensible test conditions. For instance -1 and particularly 3 should not be in range(3). Including 3 is a realistic possible error. If you partition a set into subsets < x and > x, x should not be in either, but an easy mistake would put it in either or both.
Is there any particular motivation for not putting it in?
You have 'motivation' backwards. There are an infinity of things we could add. We need a positive, substantial reason with real use cases to add something. An expression should return a particular value or return a particular expression. If it returns a value, testing that it is the correct value eliminates all exceptions. And testing for an expected exception eliminates all others. If there is an occasional needed for the proposal, one can write the same code you did, but with the possibility of excluding more than one exception. So I do not see any need for the proposal. -- Terry Jan Reedy
On 27/09/2011 19:46, Wilfred Hughes wrote:
Hi folks
I wasn't sure if this warranted a bug in the tracker, so I thought I'd raise it here first.
unittest has assertIn, assertNotIn, assertEqual, assertNotEqual and so on. So, it seems odd to me that there isn't assertNotRaises. Is there any particular motivation for not putting it in?
I've attached a simple patch against Python 3's trunk to give an idea of what I have in mind.
As others have said, the opposite of assertRaises is just calling the code! I have several times needed regression tests that call code that *used* to raise an exception. It can look slightly odd to have a test without an assert, but the singular uselessness of assertNotRaises does not make it a better alternative. I usually add a comment: def test_something_that_used_to_not_work(self): # this used to raise an exception do_something() All the best, Michael Foord
Thanks Wilfred
_______________________________________________ Python-Dev mailing list Python-Dev@python.org http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/fuzzyman%40voidspace.org.u...
-- http://www.voidspace.org.uk/ May you do good and not evil May you find forgiveness for yourself and forgive others May you share freely, never taking more than you give. -- the sqlite blessing http://www.sqlite.org/different.html
participants (9)
-
Chris Kaynor
-
exarkun@twistedmatrix.com
-
Laurens Van Houtven
-
Michael Foord
-
Oleg Broytman
-
Steven D'Aprano
-
Terry Reedy
-
Wilfred Hughes
-
Yuval Greenfield