Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.python > #30736 > unrolled thread

How can I hide my stack frames in a TestCase subclass?

Started byDavid Banks <amoebae@gmail.com>
First post2012-10-04 08:53 -0700
Last post2012-10-05 11:26 +0200
Articles 6 — 3 participants

Back to article view | Back to comp.lang.python


Contents

  How can I hide my stack frames in a TestCase subclass? David Banks <amoebae@gmail.com> - 2012-10-04 08:53 -0700
    Re: How can I hide my stack frames in a TestCase subclass? Peter Otten <__peter__@web.de> - 2012-10-05 00:41 +0200
      Re: How can I hide my stack frames in a TestCase subclass? Manuel Pégourié-Gonnard <mpg@elzevir.fr> - 2012-10-05 08:28 +0200
        Re: How can I hide my stack frames in a TestCase subclass? Peter Otten <__peter__@web.de> - 2012-10-05 10:12 +0200
          Re: How can I hide my stack frames in a TestCase subclass? Manuel Pégourié-Gonnard <mpg@elzevir.fr> - 2012-10-05 10:50 +0200
            Re: How can I hide my stack frames in a TestCase subclass? Peter Otten <__peter__@web.de> - 2012-10-05 11:26 +0200

#30736 — How can I hide my stack frames in a TestCase subclass?

FromDavid Banks <amoebae@gmail.com>
Date2012-10-04 08:53 -0700
SubjectHow can I hide my stack frames in a TestCase subclass?
Message-ID<52b17563-966c-46bc-bd77-da29e944c909@googlegroups.com>
I want to add a custom assert method to a TestCase subclass.  I tried to
copy my implementation from the unittest module so that it would match
the behaviour of the regular TestCase as closely as possible.  (I would
prefer to just delegate to self.assertEqual() but this causes even more
backtrace noise, see below.)  The unittest module seems to automatically
hide some internal details of its implementation when reporting failed
assertions.

  import unittest

  class MyTestCase(unittest.TestCase):
      def assertLengthIsOne(self, sequence, msg=None):
          if len(sequence) != 1:
              msg = self._formatMessage(msg, "length is not one")
              raise self.failureException(msg)

  class TestFoo(MyTestCase):
      seq = (1, 2, 3, 4, 5)

      def test_stock_unittest_assertion(self):
          self.assertEqual(len(self.seq), 1)

      def test_custom_assertion(self):
          self.assertLengthIsOne(self.seq)


  unittest.main()

The output of this is as such:

  amoe@vuurvlieg $ python unittest-demo.py
  FF
  ======================================================================
  FAIL: test_custom_assertion (__main__.TestFoo)
  ----------------------------------------------------------------------
  Traceback (most recent call last):
    File "unittest-demo.py", line 16, in test_custom_assertion
      self.assertLengthIsOne(self.seq)
    File "unittest-demo.py", line 7, in assertLengthIsOne
      raise self.failureException(msg)
  AssertionError: length is not one

  ======================================================================
  FAIL: test_stock_unittest_assertion (__main__.TestFoo)
  ----------------------------------------------------------------------
  Traceback (most recent call last):
    File "unittest-demo.py", line 13, in test_stock_unittest_assertion
      self.assertEqual(len(self.seq), 1)
  AssertionError: 5 != 1

  ----------------------------------------------------------------------
  Ran 2 tests in 0.000s

  FAILED (failures=2)

Note that the custom assert method causes a stack trace with two frames,
one inside the method itself, whereas the stock unittest method only has
one frame, the relevant line in the user's code.  How can I apply this
frame-hiding behaviour to my own method?

[toc] | [next] | [standalone]


#30767

FromPeter Otten <__peter__@web.de>
Date2012-10-05 00:41 +0200
Message-ID<mailman.1826.1349400392.27098.python-list@python.org>
In reply to#30736
David Banks wrote:

> I want to add a custom assert method to a TestCase subclass.  I tried to
> copy my implementation from the unittest module so that it would match
> the behaviour of the regular TestCase as closely as possible.  (I would
> prefer to just delegate to self.assertEqual() but this causes even more
> backtrace noise, see below.)  The unittest module seems to automatically
> hide some internal details of its implementation when reporting failed
> assertions.
> 
>   import unittest
> 
>   class MyTestCase(unittest.TestCase):
>       def assertLengthIsOne(self, sequence, msg=None):
>           if len(sequence) != 1:
>               msg = self._formatMessage(msg, "length is not one")
>               raise self.failureException(msg)
> 
>   class TestFoo(MyTestCase):
>       seq = (1, 2, 3, 4, 5)
> 
>       def test_stock_unittest_assertion(self):
>           self.assertEqual(len(self.seq), 1)
> 
>       def test_custom_assertion(self):
>           self.assertLengthIsOne(self.seq)
> 
> 
>   unittest.main()
> 
> The output of this is as such:
> 
>   amoe@vuurvlieg $ python unittest-demo.py
>   FF
>   ======================================================================
>   FAIL: test_custom_assertion (__main__.TestFoo)
>   ----------------------------------------------------------------------
>   Traceback (most recent call last):
>     File "unittest-demo.py", line 16, in test_custom_assertion
>       self.assertLengthIsOne(self.seq)
>     File "unittest-demo.py", line 7, in assertLengthIsOne
>       raise self.failureException(msg)
>   AssertionError: length is not one
> 
>   ======================================================================
>   FAIL: test_stock_unittest_assertion (__main__.TestFoo)
>   ----------------------------------------------------------------------
>   Traceback (most recent call last):
>     File "unittest-demo.py", line 13, in test_stock_unittest_assertion
>       self.assertEqual(len(self.seq), 1)
>   AssertionError: 5 != 1
> 
>   ----------------------------------------------------------------------
>   Ran 2 tests in 0.000s
> 
>   FAILED (failures=2)
> 
> Note that the custom assert method causes a stack trace with two frames,
> one inside the method itself, whereas the stock unittest method only has
> one frame, the relevant line in the user's code.  How can I apply this
> frame-hiding behaviour to my own method?

Move MyTestCase in a separate module and define a global variable 

__unittest = True

$ cat mytestcase.py 
import unittest

__unittest = True

class MyTestCase(unittest.TestCase):
    def assertLengthIsOne(self, sequence, msg=None):
        if len(sequence) != 1:
            msg = self._formatMessage(msg, "length is not one")
            raise self.failureException(msg)

$ cat mytestcase_demo.py 
import unittest
from mytestcase import MyTestCase

class TestFoo(MyTestCase):
    seq = (1, 2, 3, 4, 5)

    def test_stock_unittest_assertion(self):
        self.assertEqual(len(self.seq), 1)

    def test_custom_assertion(self):
        self.assertLengthIsOne(self.seq)

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

$ python mytestcase_demo.py 
FF
======================================================================
FAIL: test_custom_assertion (__main__.TestFoo)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "mytestcase_demo.py", line 11, in test_custom_assertion
    self.assertLengthIsOne(self.seq)
AssertionError: length is not one

======================================================================
FAIL: test_stock_unittest_assertion (__main__.TestFoo)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "mytestcase_demo.py", line 8, in test_stock_unittest_assertion
    self.assertEqual(len(self.seq), 1)
AssertionError: 5 != 1

----------------------------------------------------------------------
Ran 2 tests in 0.000s

FAILED (failures=2)
$ 

[toc] | [prev] | [next] | [standalone]


#30782

FromManuel Pégourié-Gonnard <mpg@elzevir.fr>
Date2012-10-05 08:28 +0200
Message-ID<k4lum6$c9q$1@thue.elzevir.fr>
In reply to#30767
Peter Otten scripsit :

> David Banks wrote:
>
>> Note that the custom assert method causes a stack trace with two frames,
>> one inside the method itself, whereas the stock unittest method only has
>> one frame, the relevant line in the user's code.  How can I apply this
>> frame-hiding behaviour to my own method?
>
> Move MyTestCase in a separate module and define a global variable 
>
> __unittest = True
>
Hum, is it documented somewhere? I can't find it in the doc. Also, I'm
curious to know what kind of magic it's using.

-- 
Manuel Pégourié-Gonnard - http://people.math.jussieu.fr/~mpg/

[toc] | [prev] | [next] | [standalone]


#30787

FromPeter Otten <__peter__@web.de>
Date2012-10-05 10:12 +0200
Message-ID<mailman.1841.1349424768.27098.python-list@python.org>
In reply to#30782
Manuel Pégourié-Gonnard wrote:

> Peter Otten scripsit :
> 
>> David Banks wrote:
>>
>>> Note that the custom assert method causes a stack trace with two frames,
>>> one inside the method itself, whereas the stock unittest method only has
>>> one frame, the relevant line in the user's code.  How can I apply this
>>> frame-hiding behaviour to my own method?
>>
>> Move MyTestCase in a separate module and define a global variable
>>
>> __unittest = True
>>
> Hum, is it documented somewhere? I can't find it in the doc. Also, I'm
> curious to know what kind of magic it's using.

I took advantage of the fact that Python is open source and had a look into 
the source code ;)

$ cd /usr/lib/python2.7/unittest
$ grep frame *.py -C2
...
result.py-
result.py-    def _is_relevant_tb_level(self, tb):
result.py:        return '__unittest' in tb.tb_frame.f_globals
result.py-
...

$ grep _is_relevant_tb_level *.py -C5
result.py-
result.py-    def _exc_info_to_string(self, err, test):
result.py-        """Converts a sys.exc_info()-style tuple of values into a 
string."""
result.py-        exctype, value, tb = err
result.py-        # Skip test runner traceback levels
result.py:        while tb and self._is_relevant_tb_level(tb):
result.py-            tb = tb.tb_next
result.py-
...

And so on. I actually used an editor, not grep -- but you get the idea.

[toc] | [prev] | [next] | [standalone]


#30794

FromManuel Pégourié-Gonnard <mpg@elzevir.fr>
Date2012-10-05 10:50 +0200
Message-ID<k4m715$74m$1@thue.elzevir.fr>
In reply to#30787
Peter Otten scripsit :

> Manuel Pégourié-Gonnard wrote:
>
>> Peter Otten scripsit :
>> 
>>> __unittest = True
>>>
>> Hum, is it documented somewhere? I can't find it in the doc. Also, I'm
>> curious to know what kind of magic it's using.
>
> I took advantage of the fact that Python is open source and had a look into 
> the source code ;)
>
Fair enough.

However, there was an implied question in the "documented" part: can
we rely on it? Isn't it considered an implementation detail (names
starting with underscores)?

> $ cd /usr/lib/python2.7/unittest
> $ grep frame *.py -C2
> ...
> result.py-
> result.py-    def _is_relevant_tb_level(self, tb):
> result.py:        return '__unittest' in tb.tb_frame.f_globals
> result.py-
> ...
>
> $ grep _is_relevant_tb_level *.py -C5
> result.py-
> result.py-    def _exc_info_to_string(self, err, test):
> result.py-        """Converts a sys.exc_info()-style tuple of values into a 
> string."""
> result.py-        exctype, value, tb = err
> result.py-        # Skip test runner traceback levels
> result.py:        while tb and self._is_relevant_tb_level(tb):
> result.py-            tb = tb.tb_next
> result.py-
> ...
>
> And so on. I actually used an editor, not grep -- but you get the idea.

Sure, thanks.

-- 
Manuel Pégourié-Gonnard - http://people.math.jussieu.fr/~mpg/

[toc] | [prev] | [next] | [standalone]


#30797

FromPeter Otten <__peter__@web.de>
Date2012-10-05 11:26 +0200
Message-ID<mailman.1846.1349429195.27098.python-list@python.org>
In reply to#30794
Manuel Pégourié-Gonnard wrote:

> However, there was an implied question in the "documented" part: can
> we rely on it? Isn't it considered an implementation detail (names
> starting with underscores)?

"Not documented" was my implied answer.

I think you have a valid use case, though, so you could make a feature 
request for an official way to hide stack frames on the bugtracker 
http://bugs.python.org or the python-ideas mailing list.

[toc] | [prev] | [standalone]


Back to top | Article view | comp.lang.python


csiph-web