简体   繁体   中英

Unit-test a method wrapper

I've got a set of actions which share some base checks. My code looks like this:

def is_valid(param): …some pretty complex things unit-tested on their own…

class BaseAction(object):
    def run(self, param):
        if not is_valid(param):
            raise ValueError(…)

        return self.do_run(param)

class Jump(BaseAction):
    def do_run(self, param): …

class Sing(BaseAction):
    def do_run(self, param): …

How should I unit-test the fact that BaseAction.run performs validation?

I think I could unit-test Jump.run and Sing.run, but then to do it properly I'd need to write tests for each subclass of BaseAction, potentially quite a lot of cases. Also this means coupling test for subclasses with a test for base class' method.

You would unit-test the is_valid() function itself. You then only have to test for the fact that .run() raises a ValueError exception when passed invalid input:

with self.assertRaises(ValueError):
    objectundertest.run(invalid_parameter)

Since you already have a unittest for is_valid() itself, your unittests for .run() do not need to focus on it's functionality. You can focus on the functionality unique to .run() .

In your case BaseAction is a unit providing a service to subclasses; I'd test this as a mock subclass:

class MockAction(BaseAction):
    run_called = None

    def do_run(self, param):
        self.run_called = param

so you can check if run indeed called do_run with the expected param value.

If you want to keep the logic in your Base class, see Martijn Pieters answer.

However, one possibility would be to restructure your code to have the validation occur in a function/class that ISN'T part of the Base class. Maybe the class that actually runs the actions itself can check those...

class Jump(object):
    def run(self, param):
        ...

def run_action(action, param):
    if not is_valid(param):
        raise ValueError(…)

    return action.run(param)

Unit testing actions is easier (you don't need to worry about the base logic), and it also won't break all your "Jump" unit tests if the "BaseAction" is somehow broken. "run_action" (you can make that a class instead of a function if you'd like) itself can be pretty easily tested (you can create a fake "Action" object).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM