Pergunta

I have some code where I'm testing for a wrapped exception, when it failed and the exception propagated I thought the error message and back trace wasn't verbose enough, primarily because it didn't tell me what was expected vs. the test, I would like details of the exception and the expectation.

I adjusted my test (see example code below). I would like to know if this type of approach is valid and if any of the Python testing or mocking frameworks allow to implement it directly? (currently I'm using unittest and mox)

One of the answers to this question briefly touches on the appropriateness of using self.fail in this scenario, but doesn't really elaborate. My assumption is that if I try to limit the test to one area I'm okay to fail the test.

Note: The code example should fail if you run it, to demonstrate the behaviour I would like to see. I'm using Python 2.7, Mox 0.5.3

import sys
import urllib2
from contextlib import closing

try:
    import lxml.etree as ET
except ImportError:
    import xml.etree.ElementTree as ET


class Defect(Exception):
    """Wrapped exception, for module error detection"""
    def __init__(self, *args):
        Exception.__init__(self, *args)
        self.wrapped_exc = sys.exc_info()


class StudioResources:
    """Dummy class"""
    def _opener(self, request, html=False):
        with closing(urllib2.urlopen(request)) as response:
            try:
                if html:
                    import lxml.html
                    return lxml.html.parse(response)
                else:
                    return ET.parse(response)
            except urllib2.HTTPError, e:
                if e.code in [400, 500]: # Bad Request, Internal Server Error
                    raise Defect, "report error to the library maintainer"
                else:
                    raise


###
# Tests
###
import unittest
import mox
import traceback
import difflib
import urllib
import httplib


def format_expectation(exc_expected=None, exc_instance=None):
    """Synopsis - For exceptions, inspired by _AssertRaisesContext

    try:
        self.assertRaises(myexc, self.studio._opener, None)
    except Exception, e:
        self.fail(format_expectation(exc_expected=myexc, exc_instance=e))
    """
    if not isinstance(exc_expected, type) or exc_instance is None:
        raise ValueError, "check __init__ args"

    differ = difflib.Differ()
    inst_class = exc_instance.__class__
    def fullname(c): return "%s.%s" % (c.__module__, c.__name__)
    diff = differ.compare(
        (fullname(inst_class),), (fullname(exc_expected),))
    _str = ("Unexpected Exception type.  unexpected:-  expected:+\n%s"
        % ("\n".join(diff),))
    return _str


class StudioTest(mox.MoxTestBase):
    def setUp(self):
        mox.MoxTestBase.setUp(self)
        self.studio = StudioResources()

    def test_opener_defect(self):
        f = urllib.addinfourl(urllib2.StringIO('dummy'), None, None)
        RESP_CODE = 501
        self.mox.StubOutWithMock(f, 'read')
        self.mox.StubOutWithMock(urllib2, 'urlopen')
        urllib2.urlopen(mox.IgnoreArg()).AndReturn(f)
        f.read(mox.IgnoreArg()).AndRaise(urllib2.HTTPError(
            'http://c.com', RESP_CODE, httplib.responses[RESP_CODE], "", None))
        self.mox.ReplayAll()
        try:
            with self.assertRaises(Defect) as exc_info:
                self.studio._opener(None)
        except Exception, e:
            traceback.print_exc()
            self.fail(format_expectation(exc_expected=Defect, exc_instance=e))
        # check the response code
        exc, inst, tb = exc_info.exception.wrapped_exc
        self.assertEquals(inst.code, RESP_CODE)
        self.mox.VerifyAll()


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

Nenhuma solução correta

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top