How to test that an exception is raised ?

S

StepH

Hi,

I've this module :

from optparse import OptionParser
import re

_version = "P1"

def writeVar(f, line):
"""Output a line in .xml format in the file f."""

f.write('\t<Var>\n')
name = line.split()[0]
adr = line.split()[3]
f.write('\t\t<Name>' + name + '</Name>\n')
f.write('\t\t<Adr>' + adr + '</Adr>\n')
f.write('\t</Var>\n')

def mps2xml(mps,verbose):
"""Convert '.mps' to '.xml'."""

try:
f = open(mps)
f.close()

xmlfile = mps + ".xml"
f = open(xmlfile, "w+")
f.write('<?xml version="1.0" ?>\n')
f.writelines('<List>\n')

pat = re.compile(".*Var.*g.*0x00.*")
lines = list(open(mps))
nbScan = nbFound = 0
for line in lines:
nbScan = nbScan + 1
if pat.match(line):
writeVar(f, line)
nbFound = nbFound + 1

f.writelines('</List>\n')
f.close()

if verbose:
print "Output to file %s..." % xmlfile
print "Lines scanned:", nbScan
print "Lines found:", nbFound

except:
if verbose:
print "FileError"

if __name__ == "__main__":
usage = "usage: %prog [options] filename"
parser = OptionParser(usage)

parser.add_option("-v", "--verbose", action="store_true",
dest="verbose")
parser.add_option("-q", "--quiet", action="store_false", dest="verbose")

(options, args) = parser.parse_args()

if len(args) != 1:
parser.error("incorrect number of arguments")
exit(1)

if options.verbose:
print "mps2xml -", _version

mps2xml(args[0],options.verbose)

And this "unittest" module :

import mps2xml
import os
import unittest

class Tests(unittest.TestCase):

def setUp(self):
self.mps = "test.mps"

def tearDown(self):
pass

def test_badFile(self):
"""Check that an exception is raised if a bad filename is passed to
mps2xml"""
self.assertRaises((IOError),mps2xml.mps2xml, "thisfiledoesntexists",
False)

def test_writeVar_Output(self):
"""Check the output of the 'writeVar' method"""

line = " irM1slotnoisePPtmp Var. g 0x0002F6"
file = open("testWriteVar.xml","w+")
mps2xml.writeVar(file, line)
file.close()

outputlines = list(open("testWriteVar.xml"))
goodlines = list(open("testWriteVar.xml.good"))
self.assertEquals(outputlines, goodlines, 'bad output format')

def test_mps2xml_Creation(self):
"""Check if test.mps.xml is created"""

mps2xml.mps2xml(self.mps, False)
self.assert_(os.path.exists(self.mps + ".xml"), 'test.mps.xml not
created')

if __name__ == '__main__':
unittest.main()

But i've prob with the 1st test : test_badFile.
When I run the test, unittest say that no error is Raised.
But when I run the mps2xml module with a bad file as arg., the exception is
well Raised.

What i'm doing wrong ?

It is because the exception in catched in the mps2xml module ?

Thanks for your helps.

StepH.
 
I

Ishwor

[snipped alot of codes that doesn't mean much ]

if you want to check for exception then it goes like this

try:
<put your code here which fails on certain exception like maybe IOError>
catch IOError:
<put a code to do something when IOError is raised>

sorry i won't bother to read your code because i can't read, i think i
am tired and need to go to bed. ;-)
 
D

Dan Perl

StepH said:
But i've prob with the 1st test : test_badFile.
When I run the test, unittest say that no error is Raised.
But when I run the mps2xml module with a bad file as arg., the exception
is
well Raised.

I assume you don't actually see the exception (you don't see the stack
traceback printed as an output) but you just see your own message
"FileError". That means that the exception was raised and caught by your
try-except statement.
What i'm doing wrong ?

It is because the exception in catched in the mps2xml module ?

With the above mentioned assumption, that must be it. Once the exception is
caught, it is caught and no other code invoking mps2xml.mps2xml (including
the assertRaises in your test) will see the exception.

Your mps2xml.mps2xml function should return a value indicating success or
failure or should re-raise the exception. You need a mechanism to let
invoking code know that it was successful or it failed. With a return code,
you should test that and not the exception. The assert you use should work
if you re-raise the exception.

And BTW, it is a bad idea to use a generic "except" statement like you do.
That catches ALL the exceptions and you will never know if a different
exception than IOError was raised. You should catch only IOError
specifically or any other exception that you may expect. You can add then
an extra "except" statement catching all the other exceptions, but only if
it is essential for your application to handle all exceptions gracefully
instead of just exiting with a stack traceback.
 
S

StepH

Thanks for you answer.
I'm new to Python (coming from C/C++).
I assume you don't actually see the exception (you don't see the stack
traceback printed as an output) but you just see your own message
"FileError". That means that the exception was raised and caught by your
try-except statement.

Yes, when i'm run mps2xml.py with a bad filename as arg., the IOError is
launched and is correctly intercepted.
With the above mentioned assumption, that must be it. Once the exception is
caught, it is caught and no other code invoking mps2xml.mps2xml (including
the assertRaises in your test) will see the exception.

Do you say that it's not possible to test (using unittest) if an exception
is well raised if the tested code catch it ?
How to solve this paradoxe ? How to automaticaly test such code ?
Your mps2xml.mps2xml function should return a value indicating success or
failure or should re-raise the exception.

1./ Cheking error-return value if not a good idea for me, cause this make
the code less clear. I don't want a code where i've to test each function
return value...
2./ If I re-raise the exception, then how to not show the traceback. My
user will became crazy if they view such error msg.
You need a mechanism to let
invoking code know that it was successful or it failed. With a return code,
you should test that and not the exception. The assert you use should work
if you re-raise the exception.

And BTW, it is a bad idea to use a generic "except" statement like you do.
That catches ALL the exceptions and you will never know if a different
exception than IOError was raised. You should catch only IOError
specifically or any other exception that you may expect. You can add then
an extra "except" statement catching all the other exceptions, but only if
it is essential for your application to handle all exceptions gracefully
instead of just exiting with a stack traceback.

It seems that there is 2 school here. I've read a lot on python, and somed
'guru' Python say that it's maybe better to use exception even for case you
can "predict", no ? Or i'm completly wrong ?
Thanks again.
StepH.
 
D

Dan Perl

StepH said:
Do you say that it's not possible to test (using unittest) if an exception
is well raised if the tested code catch it ?
How to solve this paradoxe ? How to automaticaly test such code ?

Then you need a side-effect in catching the exception. A return code would
be such a side-effect. Setting a state variable that can be checked by the
invoking code would be another such side-effect.
1./ Cheking error-return value if not a good idea for me, cause this make
the code less clear. I don't want a code where i've to test each function
return value...
2./ If I re-raise the exception, then how to not show the traceback. My
user will became crazy if they view such error msg.

But then how will the user know if the call did what it is supposed to do?
And if the user mis-used the function and used it for a file that does not
exist, how is he/she supposed to know what the problem was and why nothing
is coming out of calling your function?
It seems that there is 2 school here. I've read a lot on python, and
somed
'guru' Python say that it's maybe better to use exception even for case
you
can "predict", no ? Or i'm completly wrong ?

The IOError is an exception that you can predict and I was saying that you
should catch it, but with a "except IOError:" statement instead of the
"except:" statement that you used.
 
A

Antoon Pardon

Op 2005-01-28 said:
Thanks for you answer.
I'm new to Python (coming from C/C++).

Do you say that it's not possible to test (using unittest) if an exception
is well raised if the tested code catch it ?
How to solve this paradoxe ? How to automaticaly test such code ?

IMO you want something unittest are not designed for.

Unittest are supposed to test for particular results, not for particular
behaviour within. If the expected behaviour is that calling code doesn't
see an exception raised, then the test passed if no exception was seen.

You equally can't test which branch of an if statement was taken or
which parameter was given to a helper function in order to get to
the desired result.

That you internally raise an exception and catches it, is an
implementation detail, that normally is of no concern to
the tester.
 
S

StepH

Antoon Pardon a écrit :
IMO you want something unittest are not designed for.

So why the assertRaises function in unittest ? My goal is to test if an
exception is well raised when a bad filename is passed to the mps2xml
function.
Unittest are supposed to test for particular results, not for particular
behaviour within. If the expected behaviour is that calling code doesn't
see an exception raised, then the test passed if no exception was seen.

No (unless i don't well understand you), the expected behavior is to
launch an exception if a bad filename is passed. If no exception is
raised, this is not normal.
You equally can't test which branch of an if statement was taken or
which parameter was given to a helper function in order to get to
the desired result.

I'm agree with out on this point, but not for the exception part...
That you internally raise an exception and catches it, is an
implementation detail, that normally is of no concern to
the tester.

I'll conclude this thred here... In fact, I think I've to go-back to
theory (at least about exception)...

Thanks at all fo trying to help me. I'm new to Python, and i've not
already embrass the "python way" completly.

See you later.

StepH.
 
D

Dan Perl

StepH said:
So why the assertRaises function in unittest ? My goal is to test if an
exception is well raised when a bad filename is passed to the mps2xml
function.

It is for functions in which the exception is raised and not caught. You
can use the exception mechanism to let the code invoking your function know
that something "exceptional" has happened. It means that you "throw" that
exception to the invoking code which has to catch it. Maybe the terminology
is poorly chosen, but assertRaises does not check whether an exception is
raised inside the function but only that an exception is raised (or
"thrown", as described by other languages) from inside the function to
outside. A function does not "throw" an exception if the exception is
caught inside the function. Is that clearer now?

In java for instance, functions are actually declared to "throw" an
exception if any operation inside the function may throw that exception and
the exception is not caught inside the function. If you implement a
function A that invokes another function B and B throws an exception of type
C, then you must catch the exception C in A or you have to declare A that it
"throws C".

Hope this helps.

Dan
 
A

Antoon Pardon

Op 2005-01-28 said:
Antoon Pardon a écrit :

So why the assertRaises function in unittest?

To see if an exception is propagated to the caller.
My goal is to test if an
exception is well raised when a bad filename is passed to the mps2xml
function.

No (unless i don't well understand you), the expected behavior is to
launch an exception if a bad filename is passed. If no exception is
raised, this is not normal.

What do you mean with launch an exception? Should the exception
propagate to the caller or not? If it should your code was wrong
to catch it.
I'm agree with out on this point, but not for the exception part...

Why not? Exceptions are nothing special. Either you want to propagated
them to the caller, in which case they can be seen as somekind of result
and this can be tested for with a unittest or you don't want them to
be propagted and then they are just an implementation detail of your
unit.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,770
Messages
2,569,584
Members
45,075
Latest member
MakersCBDBloodSupport

Latest Threads

Top