3

Maybe this question is trivial, but I am still trying to warm up with unittests in python, so please have patience with me. :-) While trying to write some tests of my own, the following question araised. Assuming a function that processes nonempty strings:

class BadInputError(Exception): pass

class FooBar(object):
    def take_a_string_and_do_something(param):
        if param == '':
            raise BadInputError('param should not be an empty string')
        if param is None:
            raise BadInputError('param should not be None')
        if not isinstance(param, basestring):
            raise BadInputError('param must be of type string)
        # process nonempty string

The first thing I wanted to make sure (by unittests) is that param is only a nonempty string. So I wrote my testcases this way.

class TestFooBar(unittest.TestCase):
    def test_take_a_string_and_do_something(self):
        foo = FooBar()
        self.failUnlessRaises(BadInputError, foo.take_a_string_and_do_something, '')
        self.failUnlessRaises(BadInputError, foo.take_a_string_and_do_something, None)
        self.failUnlessRaises(BadInputError, foo.take_a_string_and_do_something, 234)

Is this acceptable or am I making heavy rookie mistake? Your feedback means a lot!

1
  • 2
    FYI, the convention for "bad input" is ValueError Commented Jun 29, 2011 at 17:33

2 Answers 2

3

Is this acceptable or am I making heavy rookie mistake?

Yes and No.

It's a fine example of how to write a unit test.

But it's a use case that shouldn't exist in your code in the first place.

class FooBar(object):
    def take_a_string_and_do_something(self, param):
        # process nonempty string
        # If they couldn't provide a non-empty string, they get an exception.

You can still test it like this.

class TestFooBar(unittest.TestCase):
    def setUp( self ):
        self.foo= FooBar()
    def test_zero_length_should_fail(self):
        self.failUnlessRaises(IndexError, foo.take_a_string_and_do_something, '')
    def test_none_should_fail(self):
        self.failUnlessRaises(TypeError, foo.take_a_string_and_do_something, None)
    def test_non_string_should_fail(self):
        self.failUnlessRaises(TypeError, foo.take_a_string_and_do_something, 234)

Notice that it's much simpler and also much more reliable, since you're not attempting to duplicate Python's extensive internal error-checking.

Sign up to request clarification or add additional context in comments.

Comments

3

If it looks like a duck it is a duck. Don't worry so much about type. Just try to use param. If you absolutely must check that it seems kosher, you can always do:

if not hasattr(param, 'replace'):
    raise ValueError('I cant work with param')

... or, if it is really important that param is something (rather than nothing):

if not param:
    raise ValueError('param should not be empty')

Quack, quack.

1 Comment

Could you add something along the lines of try: process nonempty string except Exception: raise BadInputError(e.message) as the first choice? Then the if statements as the fallback?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.