Home > Mobile >  Why unit tests fil whereas the program runs?
Why unit tests fil whereas the program runs?

Time:01-05

I'm asked to develop unit tests for a program which is such badly developed that the tests don't run... but the program does. Thus, I need to explain the reason why and I actually don't know!

Here is a piece of code that intends to represent the code I need to test:

from services import myModule1
from services.spec1 import importedFunc
from services.spec2 import getTool
from services.spec3 import getDict

class myClass(object):
    def __init__(self, param1, param2):
        self.param1 = param1
        self.param2 = param2
        self.param3 = 0
        self.param4 = 0
    
    def myMethod(self):
        try:
            myVar1 = globalDict['key1']
            myVar2 = globalDict['key2']
            
            newVar = importedFunc(par1=myVar1, par2=myVar2, par3=extVar3)
            
            calcParam = myModule1.methodMod1(self.param1)
            
            self.param3 = calcParam["keyParam3"]
            self.param4 = newVar.meth1(self.param2)
            
            globTools.send_message(self.param3, self.param4)
            
        except:
            globTools.error_message(self.param3, self.param4)

        return


class myClass2(object):
    def __init__(self, *myclass2_params):
        # some piece of code to intialize dedicated attributes
        
        self.add_objects()
    
    def add_objects(self):
        # Some piece of code
        my_class = myClass(**necessary_params)
        # Some piece of code
        return



if  __name__ == '__main__':
    globTools = getTool("my_program")
    globalDict = getDict(some_params)

    # Some piece of code
    
    my_class2 = myClass2(**any_params)

    # Some piece of code

As you can see, the problem is that the class and its methods uses global variables, defined in the main scope. And it's just a quick summary because it's actually a bit more complicated, but I hope it's enough to give you an overview of the context and help me understand why the unit test fail.

I tried to mock the imported modules, but I did not manage to a successful result, so I first tried to make it simple and just initialize all parameters. I went to this test file:

import unittest

from my_module import myClass

from services import myModule1
from services.spec1 import importedFunc
from services.spec2 import getTool
from services.spec3 import getDict

def test_myClass(unittest.TestCase):
    def setUp(self):
        globTools = getTool("my_program")
        globalDict = getDict(some_params)

    def test_myMethod(self):
        test_class = myClass(*necessary_parameters)
        test_res = test_class.myMethod()
        self.assertIsNotNone(test_res)

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

        

But the test fail, telling me 'globTools is not defined' when trying to instantiate myClass I also tried to initialize variables directly in the test method, but the result is the same

And to be complete about the technical environment, I cannot run python programs directly and need to launch a docker environment via a Jenkins pipeline - I'm not very familiar with this but I imagine it should not have an impact on the result

I guess the problem comes from the variable's scopes, but I'm not able to explain it in this case: why the test fail where as the method itself works (yes, it actually works, or at least the program globally runs without)

CodePudding user response:

It's not as bad as you think. Your setUp method just needs to define the appropriate top-level globals in your module, rather than local variables.

import unittest

import my_module
from my_module import myClass

from services import myModule1
from services.spec1 import importedFunc
from services.spec2 import getTool
from services.spec3 import getDict

class test_myClass(unittest.TestCase):
    def setUp(self):
        my_module.globTools = getTool("my_program")
        my_module.globalDict = getDict(some_params)

    def test_myMethod(self):
        test_class = myClass(*necessary_parameters)
        test_res = test_class.myMethod()
        self.assertIsNotNone(test_res)

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

Depending on how the code uses the two globals, setUpClass might be a better place to initialize them, but it's probably not worth worrying about. Once you have tests for the code, you are in a better position to remove the dependency on these globals from the code.

  • Related