2

I have a body of python code that contains inline functions within functions. I'd like to unit test the make_exciting inner function, so I'm trying to figure out how to invoke it directly.

def say_something_exciting(name, phrase):
    def make_exciting(phrase):
        return phrase + "!"
    return "%s says '%s'" % (name, make_exciting(phrase))

Function say_something_exciting is written at the top level of a .py file, and is not inside a class. The py file is in the org.something module. Tried:

  • Invoking the function directly via org.something.say_something_exciting.make_exciting("Hello") - error: 'function' object has no attribute 'make_exciting'
  • Inspecting dir(org.something.say_something_exciting) and org.something.say_something_exciting.__dict__ for any paths to traverse, didn't see make_exciting anywhere.
  • internal_function = org.something.say_something_exciting.__dict__.get('make_exciting'), but internal_function is None.

How can I access (unit test) this inner function? This may suggest what I'm asking isn't possible. I'm generally familiar with unit testing and how to use the unittest module; accessing the function is the problem. If it's not possible, how should I re-write this code to support testing (if other than promote the inner function to a top-level function)?. Thanks!

UPDATE: In Java I often give class methods default/package visibility so they're less visible but still accessible to unit tests, looking for a python equivalent.

Community
  • 1
  • 1
Brad Wehrwein
  • 155
  • 2
  • 9
  • Why do you need to test it separately? – Peter Wood Aug 14 '15 at 23:23
  • What are you actually trying to do? This looks like a manufactured example; if it's not, then drop the inner function and just do `def say_something_exciting(name, phrase): return "%s says '%s'" % (name, phrase + '!')`. – Cyphase Aug 14 '15 at 23:30
  • This is a manufactured example (and my first post! how fun). For the sake of discussion let's assume I can't rewrite the code to remove the inner function. Otherwise that'd be my first thought too @Cyphase – Brad Wehrwein Aug 15 '15 at 23:18
  • I don't see why that would be, but if so, as, @PeterWood asked, why do you need to test it separately? – Cyphase Aug 15 '15 at 23:29
  • I'm trying to understand what's possible so I can adapt my coding style to support testing. In Java I often give methods default visibility so they're less visible but still accessible to testing - there seems to be no analogy here. Maybe the takeaway is: if it's a "unit" that needs independent testing than it isn't an internal detail at all, and should be exposed publicly and tested "standardly". – Brad Wehrwein Aug 16 '15 at 02:39

1 Answers1

1

I don't think you can.

You'll need to return the inner function, or bind it elsewhere. It gets ugly though. You can bind the declared function to somewhere else, from inside the function:

import testmodule
testmodule.testfunc = make_exciting

Or you can return it, for example when a keyword-argument is given, such as export=True.

Berserker
  • 1,112
  • 10
  • 26
  • Expose the private function by modifying it and coupling it to some global reference? I agree it's messy. I wanted to understand if it's possible to test this function as-as, without modifying it. – Brad Wehrwein Aug 15 '15 at 23:26
  • Yeah, that's about your only bet. Unless you want to go meta and extract the function definition as string, compile it inline for the unittest and use that... – Berserker Aug 15 '15 at 23:34