Testing for side-effects in python

2019-06-07 17:32发布

I want to check that my function has no side-effects, or only side-effects affecting precise variables. Is there a function to check that it actually has no side-effects (or side-effects on only certain variables)?

If not, how can I go about writing my own as follows:

My idea would be something like this, initialising, calling the function under test, and then calling the final method:

class test_side_effects(parents_scope, exclude_variables=[]):
    def __init__():
        for variable_name, variable_initial in parents_scope.items():
            if variable_name not in exclude_variables:
                setattr(self, "test_"+variable_name, variable_initial)
    def final(self, final_parents_scope):
        for variable_name, variable_final in final_parents_scope.items():
            if variable_name[:5] is "test_" and variable_name not in exclude_variables:
                assert getattr(self, "test_"+variable_name) is variable_final, "Unexpected side effect of %s from %s to %s" % (variable_name, variable_initial, variable_final)

#here parents_scope should be inputted as dict(globals(),**locals())

I'm unsure if this is precisely the dictionary I want...

Finally, should I be doing this? If not, why not?

1条回答
我想做一个坏孩纸
2楼-- · 2019-06-07 17:59

I'm not familiar with the nested function testing library that you might be writing a test with, but it seems like you should really be using classes here (i.e. TestCase in many frameworks).

If your question then, is relating to getting the parent variables in your TestCase, you could get the __dict__ (It wasn't clear to me what the "Parent" variables you were referring to.

UPDATE: @hayden posted a gist to show the use of parent variables:

def f():
    a = 2
    b = 1
    def g():
        #a = 3
        b = 2
        c = 1
        print dict(globals(), **locals()) #prints a=1, but we want a=2 (from f)
    g()
a = 1
f()

If this is converted to a dictionary, then the problem is solvable with:

class f(object): # could be unittest TestCase
    def setUp(self, a=2, b=1):
        self.a = a
        self.b = b

    def g(self):
        #a = 3
        b = 2
        c = 1
        full_scope = globals().copy()
        full_scope.update(self.__dict__)
        full_scope.update(locals())
        full_scope.pop('full_scope')
        print full_scope # print a = 1

my_test = f()
my_test.setUp(a=1)
my_test.g()

You are right to look for a tool which has already implemented this. I am hopeful that somebody else will have an already implemented solution.

查看更多
登录 后发表回答