Running unit tests on nested functions

I come from the Java world, where you can hide variables and functions and then run unit tests against them using reflection. I have used nested functions to hide implementation details of my classes so that only the public API is visible. I am trying to write unit tests against these nested functions to make sure that I don't break them as I develop. I have tried calling one of the nested functions like:

def outer():
    def inner():
        pass

outer.inner()

which results in the error message:

AttributeError: 'function' object has no attribute 'inner'

Is there a way for me to write unit tests against these nested functions? If not, is there a way to trigger the name munging for function names like you can for class variables by prefixing them with __?


Asked by: Maddie843 | Posted: 28-01-2022






Answer 1

inner doesn't exist until outer makes it. You should either move inner up to a toplevel function for testability, or have the outer test test all the possible execution paths of itself and inner.

Do note that the inner function isn't a simple function, it's a closure. Consider this case:

def outer(a):
    b = compute_something_from(a)
    def inner():
        do_something_with(a, b)

That's the standard testability trade-off. If your cyclomatic complexity is too high, your tests will be too numerous.

Answered by: Catherine810 | Posted: 01-03-2022



Answer 2

I have written a small helper module which allows exactly this:

Examples of nested functions:

def f(v1):
  v2 = 1
  def g(v3=2):
    return v1 + v2 + v3 + 4
  def h():
    return 16
  return g() + h() + 32

class C(object):
  def foo(self):
    def k(x):
      return [ self, x ]
    return k(3)

def m():
  vm = 1
  def n(an=2):
    vn = 4
    def o(ao=8):
      vo = 16
      return vm + an + vn + ao + vo
    return o()
  return n()

These can be unit tested using this kind of code:

import unittest
from nested import nested

class TestNested(unittest.TestCase):
  def runTest(self):
    nestedG = nested(f, 'g', v1=8, v2=1)
    self.assertEqual(nestedG(2), 15)
    nestedH = nested(f, 'h')
    self.assertEqual(nestedH(), 16)
    nestedK = nested(C.foo, 'k', self='mock')
    self.assertEqual(nestedK(5), [ 'mock', 5 ])
    nestedN = nested(m, 'n', vm=1)
    nestedO = nested(nestedN, 'o', vm=1, an=2, vn=4)
    self.assertEqual(nestedO(8), 31)

def main(argv):
  unittest.main()

if __name__ == '__main__':
  import sys
  sys.exit(main(sys.argv))

The small helper module nested looks like this:

import types

def freeVar(val):
  def nested():
    return val
  return nested.__closure__[0]

def nested(outer, innerName, **freeVars):
  if isinstance(outer, (types.FunctionType, types.MethodType)):
    outer = outer.func_code
  for const in outer.co_consts:
    if isinstance(const, types.CodeType) and const.co_name == innerName:
      return types.FunctionType(const, globals(), None, None, tuple(
          freeVar(freeVars[name]) for name in const.co_freevars))

Answered by: Sydney314 | Posted: 01-03-2022



Answer 3

The Python convention is to name "private" functions and methods with a leading underscore. When you see a leading underscore, you know not to try and use it.

Remember, Python is not Java.

Answered by: Ted660 | Posted: 01-03-2022



Answer 4

I don't think that there is any chance to access inner() from the extern namespace.

However, in my opinion the fact that you keep inner() nested implies that the only "contract" that really matters is outer()'s one. inner() is part of the implementation, and you shouldn't want to test the implementation. If you really want to test inner(), do extensive tests on outer() with data that will involve all the functionalities of inner().

Answered by: Joyce332 | Posted: 01-03-2022



Answer 5

I had the same doubt and found a way to get tests going for inner functions.

def outer():
    def inner():
        pass

    if __debug__:
        test_inner(inner)
        # return

def test_inner(f):
     f() # this calls the inner function

outer()

Basically you can send the inner function as a parameter to the outside and test it as you wish. When calling outer(), your test will run, and since it's a closure, it will preserve any extra property from the outer function (like variables). Using a list, you can send as many functions as you wish. To ignore the if, an option is to run the code like that:

python -O code.py

Answered by: Chloe541 | Posted: 01-03-2022



Answer 6

No way to get inner function from outer function object (see the other replies!). Yet both unit tests and closures have made (for me at least) amazing developer performance improvements. Can we have both? Can we test nested functions in isolation?

Not easily.

However, such could seemingly be achieved with use of python modules parser, ast, or tokenizer to dice up the code itself, extracting inner functions (by some path through the nesting), and allowing tests to run them with state from enclosing functions (values for closed-over names) and stubs/mocks for more-nested functions (defined within the test target).

Anybody know of anything like this? Googling failed to find anything.

Answered by: Blake800 | Posted: 01-03-2022



Answer 7

I ran into an interesting case where I was able to run a unit test on a nested function using MagicMock. The key was that the nested function was being sent as an argument to another function that I had access to. To keep with the OP's example:

# my_app.py

def util(func):
    # run some logic using func

def outer():
    def inner():
        pass

    util(inner)

Being able to mock the util function allowed access to the call arguments, which in this case happens to be the inner function:

def test_inner
    # Arrange
    mock_util = MagicMock()

    with patch.object(my_app, 'util', mock_util):
        outer() # run the outer function to capture the util call with MagicMock

    inner_function = mock_util.call_args[0][0]

    # Act
    inner_function() # run the inner function for testing

    # Assert
    # make whatever assertions you would like

I got lucky this time, in that I did not need to alter the code that I was asked to test. @Victor-Barroso's answer features an intentional way to do something similar, for those who are looking for options. Although, if you are going to alter the code, you may as well follow @Dustin's advice or any of the other good answers on this question.

Answered by: Marcus351 | Posted: 01-03-2022



Similar questions

python - Running functions from a list issue

I am wondering how to run functions from a list, and calling them using the random module, but I can't seem to get it to work can anyone help? Here is an example below. import random def word1(): print "Hello" def word2(): print "Hello again" wordFunctList = [word1, word2] def run(): printWord = random.randint(1, len(wordFunctList))-1 wordFunctList[printWord] run() run()...


python - Thread for each item in list, running two functions for each item in list

I'll preface this with I'm new to threading. I have tried a couple different ways, and come sort of close to success, but not really. I have a list that is created from a file as such: with open(server_file, 'rU') as fi: servers = fi.read().split('\n') I have two functions grabdata() and runcheck() that I need to be run for each item in the list, each pair (grabdata and then ru...


python - Functions running when not being called

This question already has answers here:


python - Call functions that are inside a running thread

I have this code: def Spawn(nick,password): Active=True s=socket.socket(socket.AF_INET,socket.SOCK_STREAM) s.connect(('asdasd',asdasdasd)) s.send('PASS '+password+'\r\n') s.send('NICK '+nick+'\r\n') s.send('JOIN '+channel+'\r\n') while True: buf=s.recv(1024) if('PRIVMSG' in buf): sender=buf.split('!',1)[0].split(':') message=buf.split(':'...


python - What is the running time of these functions?

What is the running time? def a(n): if n % 2 == 0: return n else: return a(n/2) My guess T(n) = T(n/2) + 1, then use master theorem. How about this function: def b(n): for i in range(n): print(a(i)) This is my guess. T(n) = nT(n/2) + 1


Python functions running too fast?

I'm writing a script (Python 2.7.10) to log in to networking devices and gather diagnostics information that the vendor can potentially ask for. It's fairly straightforward, but I've run into an interesting problem (at least for me). I've exhausted my limited knowledge on this. This is the piece of the code that calls the functions to run: elif args.hostname and args.username and args.jtac ...


python - Why is one of my functions running twice?

The function search_for_song(pbody) is running twice, i can't figure out why. would like some help, just started learning python a few days ago. Here's the full code: #a bot that replies with youtube songs that were mentioned in the comments import traceback import praw import time import sqlite3 import requests from lxml import html import socket import errno import re import urllib from bs4 import...


python - Functions aren't running

My functions in Python aren't returning values that I expect them to. Here is a MWE: a = 6 b = 18 c = 0 def random_function(c): c = b/a return c random_function(c) print(c) I expect this function to print 3, but instead it prints 0. I have just updated from 2.7 to 3.6 and this would have worked in 2.7 - what am I doing wrong?


python - Running nested functions using numba

I am trying to use numba recently to speedup parts of my code in python. I was trying to run function 1 from inside function 2 while they are both compiled with numba but it is not working. Here is my code: import numba as nb from math import acos from time import time @nb.jit("void()") def myfunc(): s = 0 for i in range(10000000): s += acos(0.5) print('The sum is: ', s) @nb.jit("void...


python - Running unit tests with pytest on functions

I am trying to run a unit test on a set of functions. The functions return multiple pandas dataframes. How would I approach asserting equality between multiple dataframes using pytest? Appreciate your help! @pytest.fixture def function_to_test(): df1 = pd.DataFrame({'random': ['1'],'columns': ['One']}) df2 = pd.DataFrame({'random': ['1'],'columns': ['One']}) df3 = pd.DataFrame({'...


python - Running different functions based on the user's input

I am new to Pycharm, and Python as a whole, and for my first project I decided to do a random name/object selector which chooses a name from a pre-made variable of letters and prints that result. I wanted to expand on this and have the user either use the default names in the code or add their own names to be used. I gave it my best effort but when it came to the script running 1 of two functions I was unable to figure ou...


python - 2 functions in scrapy spider and the second one not running

I am using scrapy to get the content inside some urls on a page, similar to this question here: Use scrapy to get list of urls, and then scrape content inside those urls I am able to get the subURLs from my start urls(first def), However, my second def doesn't seem to be passing throu...


functions in list loop not running one by one in python

i have 5+ functions, so i want to run all functions one by one in series. like if i put loop range = 10 and i have 5 functions on list, so func1() should run once and func2() on 2nd and func3() on 3rd range and it should be in loop until range = 10 reaches. loop = 10 funcs = [func1(), func2(), func3(), func4(), func5()] for i in range(funcs,loop): print(i) i have trie...


python - Issue running functions in pygame

import pygame import random import time pygame.init() backX = 1000 backY = 600 screen = pygame.display.set_mode((backX, backY)) score = 0 white = (255, 255, 255) green = (0, 255, 0) blue = (0, 0, 128) timespent = 0 pygame.display.set_caption('Monkey Simulator') # game name pygame.font.init() # you have to call this at the start, # if you want to use this module. myfont = pygame.font.SysFont('Comic Sans MS', 30)...


python - Running two functions at the same time?

from turtle import * a = Screen() b = Turtle() c = Turtle() def one(): b.forward(100) def two(): c.forward(-100) I want b and c moving away from each other at the same time, tried lots of stuff but I cant figure it out. Help me out please.


Why does running java functions from a python script crash

I am trying to use java classes in a python script by importing jpype, however, every time I do so, the execution crashes. I am running the script using python3 on macOS, and JVM is zulu-8.jdk. Here is the script import jpype as jp jp.startJVM(jp.getDefaultJVMPath(), "-ea") jp.java.lang.System.out.println("hello world") jp.shutdownJVM() Crash mess...


.net - Running CPython functions from C#

I'm working on a project where I need to be able to run a python function that depends on SciPy/NumPy. Due to this being an add-on to a project already in progress, using IronPython would not be an option. Additional info: Python.NET seemed to be a good fit, but I was unable to get the return value from RunString() (it would only return NULL). Passing arguments and ...


Running python functions in Eclipse command line

I would like to run a python function using the command line in Eclipse (if it exists), just like the normal Python Shell (IDLE) or programs such as MATLAB. How would I do that.


python - running different classes and functions

Im a threading noob. I'm trying to run a function as a thread that weighs something, and another that checks that the weight is sensible -- and shuts down both threads if the weights are not. This is running on a beagleboneblack -- but that is probably not relevant. For the purposes of simplicity, I include here code that produces the same sort of undesired behaviour -- but is simplified. from time import ...


python - Running functions from a list issue

I am wondering how to run functions from a list, and calling them using the random module, but I can't seem to get it to work can anyone help? Here is an example below. import random def word1(): print "Hello" def word2(): print "Hello again" wordFunctList = [word1, word2] def run(): printWord = random.randint(1, len(wordFunctList))-1 wordFunctList[printWord] run() run()...


python - Thread for each item in list, running two functions for each item in list

I'll preface this with I'm new to threading. I have tried a couple different ways, and come sort of close to success, but not really. I have a list that is created from a file as such: with open(server_file, 'rU') as fi: servers = fi.read().split('\n') I have two functions grabdata() and runcheck() that I need to be run for each item in the list, each pair (grabdata and then ru...


python - Running functions defined within classes

I have a python class which houses some info. I have another file which some of these functions refer to. My get_date , is working fine however, none of my other functions seem to be working. I am getting the error AttributeError: PVData instance has no attribute 'time' when calling the time function. class PVData: def __init__(self): self.date = yesterday() se...


python - Functions running when not being called

This question already has answers here:


python - Call functions that are inside a running thread

I have this code: def Spawn(nick,password): Active=True s=socket.socket(socket.AF_INET,socket.SOCK_STREAM) s.connect(('asdasd',asdasdasd)) s.send('PASS '+password+'\r\n') s.send('NICK '+nick+'\r\n') s.send('JOIN '+channel+'\r\n') while True: buf=s.recv(1024) if('PRIVMSG' in buf): sender=buf.split('!',1)[0].split(':') message=buf.split(':'...


python - What is the running time of these functions?

What is the running time? def a(n): if n % 2 == 0: return n else: return a(n/2) My guess T(n) = T(n/2) + 1, then use master theorem. How about this function: def b(n): for i in range(n): print(a(i)) This is my guess. T(n) = nT(n/2) + 1


Python functions running too fast?

I'm writing a script (Python 2.7.10) to log in to networking devices and gather diagnostics information that the vendor can potentially ask for. It's fairly straightforward, but I've run into an interesting problem (at least for me). I've exhausted my limited knowledge on this. This is the piece of the code that calls the functions to run: elif args.hostname and args.username and args.jtac ...


variadic functions - Passing on named variable arguments in python

Say I have the following methods: def methodA(arg, **kwargs): pass def methodB(arg, *args, **kwargs): pass In methodA I wish to call methodB, passing on the kwargs. However, it seems that if I define methodA as follows, the second argument will be passed on as positional rather than named variable arguments. def methodA(arg, **kwargs): methodB("arg...


storing unbound python functions in a class object

I'm trying to do the following in python: In a file called foo.py: # simple function that does something: def myFunction(a,b,c): print "call to myFunction:",a,b,c # class used to store some data: class data: fn = None # assign function to the class for storage. data.fn = myFunction And then in a file called bar.py: import foo d = foo.data d.fn(1,2,3)


python - Porting MATLAB functions to Scilab. How do I use symbolic?

I'm porting some MATLAB functions to Scilab. The cool thing is that there is a conversion toolbox that make things very easy. The problem is I did not find the counterpart to...


python - Parsing Functions

I'm making a script parser in python and I'm a little stuck. I am not quite sure how to parse a line for all its functions (or even just one function at a time) and then search for a function with that name, and if it exists, execute that function short of writing a massive list if elif else block.... EDIT This is for my own scripting language that i'm making. its nothing very complex, but i have a...


python - How to call java objects and functions from CPython?

I have a python program, which runs on the CPython implementation, and inside it I must call a function defined in a java program. How can I do this? It would be nice to be able to use some java objects too. Jython is not an option. I must run the python part in CPython.


Passing functions which have multiple return values as arguments in Python

So, Python functions can return multiple values. It struck me that it would be convenient (though a bit less readable) if the following were possible. a = [[1,2],[3,4]] def cord(): return 1, 1 def printa(y,x): print a[y][x] printa(cord()) ...but it's not. I'm aware that you can do the same thing by dumping both return values into temporary variables, but it doesn't seem as elega...


Passing self to class functions in Python

This question already has answers here:


c# - Import python functions into a .NET language?

I am a C# .NET programmer and am learning Python. I have downloaded IronPython, and know that it can call into .NET libraries. I'm wondering whether there is a way to do the reverse, that is to call into some existing "classic" Python libraries in my C# code, maybe using .NET Interop. I'd like to be able to access functions in libraries such as pygame.


Python Hash Functions

What is a good way of hashing a hierarchy (similar to a file structure) in python? I could convert the whole hierarchy into a dotted string and then hash that, but is there a better (or more efficient) way of doing this without going back and forth all the time? An example of a structure I might want to hash is: a -> b1 -> c -> 1 -> d a -> b2 -> c -> 2 -> d a -> c ...


Passing functions with arguments to another function in Python?

This question already has answers here:






Still can't find your answer? Check out these communities...



PySlackers | Full Stack Python | NHS Python | Pythonist Cafe | Hacker Earth | Discord Python



top