2

I've got a set of tests, and I've found that I'm copying/pasting a lot of code from class to class, so I want to make a base class to remove this.

To do this effectively, I need to make the module-under-test's function to call be accessible to the base class. It seems like it should be simple to do, but what I've found is that if my child class specifies a global variable that is the function to test, the base class, when it calls it, inserts 'self' as parameter zero, resulting in TypeError: FooBar() takes exactly 2 arguments (3 given)

My Code:

import unittest    
import moduleOfFunctionsToTest as uut

class Base_Test_Class( unittest.TestCase ):
  def setUp( self ):
    # Common test suite setup
    return

  def runFcn( self ):
    return self.uutFcn( "foo", self.bar )

  # other common fucntions.

class TheFirstTestClass( Base_Test_Class ):
  uutFcn = uut.FooBar
  bar = "0"

  def test_SomeCode( self ):
    self.runFcn

How can I call self.uutFcn without self being inserted? I've tried passing the value via a constructor, but that caused other headaches (which I may need to revisit if that is correct path to take.)

TIA!

PfunnyGuy
  • 750
  • 9
  • 22
  • 1
    Have you tried `TheFirstTestClass.uutFcn(arguments)`? Also saying return = stuff should break things and if it doesn't it's really poor style... – Eli Berkowitz Apr 05 '19 at 01:48
  • 3
    Something else to consider is making a `@staticmethod` or `@classmethod` depending on your needs but at a glance I'm not sure either really fits your needs :) https://stackoverflow.com/questions/136097/what-is-the-difference-between-staticmethod-and-classmethod – Eli Berkowitz Apr 05 '19 at 01:58
  • @EliBerkowitz - Thanks! I didn't see that typo. `return = fcn()` won't work. I condensed the code. I typically do `x = fcn(); return x` so that single-step debugging allows you to see the return value before returning. – PfunnyGuy Apr 08 '19 at 13:42
  • 1
    Yes, doing `uutFcn = staticmethod(uut.FooBar)` would solve your problem. – jdehesa Apr 08 '19 at 13:43
  • I've found 3 ways to make it work. 1) `@staticmethod` decorator on the function I'm testing; but it requires a change to the module I'm testing, and I really only want to make changes that fix bugs, not make the code testable. 2) create a function in the child class that the base class calls, similar to creating a base class pure virtual function in C++. 3) @jdehesa suggestion, changing the assignment of uutFcn. @jdehesa, if you want to make an answer I'll accept it. – PfunnyGuy Apr 08 '19 at 14:50

1 Answers1

1

One way to solve it is using staticmethod in the definition of uutFcn:

import unittest    
import moduleOfFunctionsToTest as uut

class Base_Test_Class( unittest.TestCase ):
  def setUp( self ):
    # Common test suite setup
    return

  def runFcn( self ):
    return self.uutFcn( "foo", self.bar )

  # other common fucntions.

class TheFirstTestClass( Base_Test_Class ):
  uutFcn = staticmethod(uut.FooBar)
  bar = "0"

  def test_SomeCode( self ):
    self.runFcn()

This works because staticmethod ensures that the given function is always executed with no additional parameters, no matter whether you call it through the class or an instance, so the signature of uut.FooBar would remain unchanged.

jdehesa
  • 58,456
  • 7
  • 77
  • 121