Python: best way to test a single method of a class

Viewed 21948

I have a class like the following:

class A:
    def __init__(self, arg1, arg2, arg3):
        self.a=arg1
        self.b=arg2
        self.c=arg3
        # ...
        self.x=do_something(arg1, arg2, arg3)
        self.y=do_something(arg1, arg2, arg3)

        self.m = self.func1(self.x)
        self.n = self.func2(self.y)
        # ...

    def func1(self, arg):
        # do something here

    def func2(self, arg):
        # do something here

As you can see, initializing the class needs to feed in arg1, arg2, and arg3. However, testing func1 and func2 does not directly require such inputs, but rather, it's simply an input/output logic.

In my test, I can of course instantiate and initialize a test object in the regular way, and then test func1 and func2 individually. But the initialization requires input of arg1 arg2, arg3, which is really not relevant to test func1 and func2.

Therefore, I want to test func1 and func2 individually, without first calling __init__. So I have the following 2 questions:

  1. What's the best way of designing such tests? (perferably, in py.test)
  2. I want to test func1 and func2 without invoking __init__. I read from here that A.__new__() can skip invoking __init__ but still having the class instantiated. Is there a better way to achieve what I need without doing this?

NOTE:

There have been 2 questions regarding my ask here:

  1. Is it necessary to test individual member functions?
  2. (for testing purpose) Is it necessary to instantiating a class without initializing the object with __init__?

For question 1, I did a quick google search and find some relevant study or discussion on this:

We initially test base classes having no parents by designing a test suite that tests each member function individually and also tests the interactions among member functions.

For question 2, I'm not sure. But I think it is necessary, as shown in the sample code, func1 and func2 are called in __init__. I feel more comfortable testing them on an class A object that hasn't been called with __init__ (and therefore no previous calls to func1 and func2).

Of course, one could just instantiate a class A object with regular means (testobj = A()) and then perform individual test on func1 and func2. But is it good:)? I'm just discussing here as what's the best way to test such scenario, what's the pros and cons.

On the other hand, one might also argue that from design perspective one should NOT put calls to func1 and func2 in __init__ in the first place. Is this a reasonable design option?

3 Answers

I agree with previous comments that it is generally better to avoid this problem by reducing the amount of work done at instantiation, e.g. by moving func1 etc calls into aconfigure(self) method which should be called after instantiation.

If you have strong reasons for keeping calls to self.func1 etc in __init__, there is an approach in pytest which might help.

(1) Put this in the module:

_called_from_test = False

(2) Put the following in conftest.py

import your_module

def pytest_configure(config):
    your_module._called_from_test = True

with the appropriate name for your_module.

(3) Insert an if statement to end the execution of __init__ early when you are running tests,

   if _called_from_test:
      pass
   else:
      self.func1( ....)

You can then step through the individual function calls, testing them as you go.

The same could be achieved by making _called_from_test an optional argument of __init__.

More context is given in the Detect if running from within a pytest run section of pytest documentation.

Related