[Baypiggies] Unittest magic -- how to get into that exception handler?

Bob Van Zant bob at eventbrite.com
Tue Mar 29 18:31:12 CEST 2011


> And I have to build a parallel mock object with precise choreography in order to drive the
> execution to some point.
This is a sign that the code under test wasn't designed for unit
testing. Consider refactoring this code to be more easily tested. In
the future design for test from square 1 and you won't have this
problem.

-Bob


>
> Wai Yip
>
>
>> Hey Wai Yip!
>> I think a Mock is exactly what you want. In fact I think your marker
>> proposal is basically a specialized form of monkey patching in mocks
>> that return specified values. The mocking library I reference below
>> does a good job of this.
>>
>> In the example you've given it's sort of a pain in the butt to use a
>> mock because you have to monkey patch my_processing in order to mock
>> it out. If your function took the processing function as an argument
>> you could very easily:
>>
>> def super_bogus_processing():
>>    return None
>> def bad_len_processing():
>>    return ['list of length 1']
>>
>> def myfunc(processor_func=my_processing):
>>    result = processor_func()
>>    ...
>>
>> self.assertRaises(RuntimeException, myfunc, super_bogus_processing)
>> self.assertRaises(RuntimeException, myfunc, bad_len_processing)
>>
>>
>> super_bogus_processing exploits an unhandled exception in your sample.
>> len of None raises TypeError.
>>
>> I think in this particular example, with code that's designed for it,
>> mocking is really the way to go.
>>
>> A shameless plug for a mocking framework named ditto:
>> http://code.google.com/p/ditto/. This one does a good job of Mocking
>> existing classes and modeling their interface at runtime rather than
>> creating some arbitrary interface that never fails when an unknown
>> method or attribute is accessed.
>>
>> -Bob
>>
>>
>>
>> On Mon, Mar 28, 2011 at 4:52 PM, Tung Wai Yip <tungwaiyip at yahoo.com>
>> wrote:
>>>
>>> In my code there is a lot of result checking and exception handling code,
>>> e.g.
>>>
>>>
>>> def myfunc():
>>>   result = my_processing()
>>>   if len(result) != 2:
>>>       raise RuntimeException("Result not right, len=%s" % len(result))
>>>
>>>   # verified result is a sequence of len 2 as documented
>>>   ...
>>>
>>>
>>> Normally, this exception handling code is never run because the error
>>> condition does not happen. But it is never a good idea to ship code that
>>> has
>>> never been run. Many times I get embarrassing problem like the error
>>> message's formating string does not match the parameter or just typo.
>>> Instead of helping, the checking code creates further complication. This
>>> is
>>> even more problematic for a dynamic language like Python with less
>>> compile
>>> time checking.
>>>
>>> So I really want to get the code to run, using automatic unit testing or
>>> other means. The conventional way to handle this is to create mock object
>>> for things like `my_processing`. I'm not a big fan of mock object. First
>>> of
>>> all I have a lot of those situations and thus a lot of things to mock. I
>>> don't like the extra layer of indirection and I find mock object are
>>> often
>>> very hackish. Plus it creates a lot of maintenance issue. When I refactor
>>> the logic, I also have to take care of the mock object or they will be
>>> the
>>> first to break.
>>>
>>> I have some idea that is to use annotation to inject code to push the
>>> execution into some path. That requires some language magic I wonder if
>>> it
>>> is feasible. For example, I'm thinking of introducing some marker like
>>> @unittest_magic.
>>>
>>>
>>> def myfunc():
>>>   result = my_processing()
>>>   @unittest_magic(name="my_processing_result_validation")
>>>   if len(result) != 2:
>>>       raise RuntimeException("Result not right, len=%s" % len(result))
>>>
>>>   # verified result is a sequence of len 2
>>>   ...
>>>
>>>
>>> Then elsewhere I can invoke it and specified it to take on any arbitrary
>>> variable value when the execution has reached the point by:
>>>
>>>  run_test(myfunc, "my_processing_result_validation", result=["dummy"])
>>>
>>>
>>> I think this is fairly lightweight and localized magic compares to mock
>>> object. What do you think? Is it feasible? Or do you have other strategy
>>> to
>>> handle those situation?
>>>
>>>
>>> Wai Yip
>>> _______________________________________________
>>> Baypiggies mailing list
>>> Baypiggies at python.org
>>> To change your subscription options or unsubscribe:
>>> http://mail.python.org/mailman/listinfo/baypiggies
>


More information about the Baypiggies mailing list