1

I want to make a function that can be used in other unit tests in the script. Here is what I mean:

class TestSomething(unittest.TestCase):
    def __init__(self, title, description):
        self.title = title
        self.description = description
        self.tag = 'ts'

class TestSomething2(unittest.TestCase):
    def __init__(self, title, description):
        self.title = title
        self.description = description
        self.tag = 'ts2'

class TestWhatever(unittest.TestCase):
    def test_whatever(self):
        blah = TestSomething('Happy Gilmore', 'golf movie')
        AttributeCheck(blah, 'Happy Gilmore', 'golf movie', 'ts')

class TestWhatever2(unittest.TestCase):
    def test_whatever(self):
        blah = TestSomething2('Toy Story', 'kids movie')
        AttributeCheck(blah, 'Toy Story', 'kids movie', 'ts2')

class AttributeCheck(unittest.TestCase):
    def __init__(self, element, title, description, tag):
        super(AttributeCheck, self).__init__()
        self.assertEqual(element.title, title)
        self.assertEqual(element.description, description)
        self.assertEqual(element.tag, tag)

    def runTest(self):  # this is what causes problems
        print 'ok'


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

The error I get is: TypeError: __init__() takes at least 3 arguments (2 given) It basically tries to run the AttributeCheck and I think it runs runTest as if it were a test. However, I need the def runTest(self): because if I don't have it then I get the: ValueError: no such test method in <class 'AttributeCheck'>: runTest

4
  • 1
    Why does AttributeCheck inherit from TestCase if you don't want the test runner to treat it like a test? Commented Sep 20, 2017 at 2:45
  • @ryanh119 The above code is watered down a little bit. I want to pass in multiple values to AttributeCheck various times and have AttributeCheck run tests on the values that get passed in to make sure they are correct. Commented Sep 20, 2017 at 3:07
  • @ryanh119 I updated the post to give you a better idea of what I am trying to do. Commented Sep 20, 2017 at 13:27
  • 1
    Thanks for the update, I think I see what you're trying to do. I'm working on an answer. Commented Sep 20, 2017 at 16:47

1 Answer 1

2

You're using unittest.TestCase in a way that I haven't seen before, and I think is inconsistent with the documentation. My answer uses TestCase how I normally use it, hopefully it answers your question.

As far as having a function that can be used in multiple tests in the script, you can add a function to your test class that does a check for you. If it doesn't have "test" in the name, it won't be run as a test:

class TestWhatever(unittest.TestCase):
    def test_whatever_does_something(self):
        instance = Whatever('Happy Gilmore', 'golf movie', 'ts')
        self._check_attributes(instance, 'Happy Gilmore', 'golf movie', 'ts')

    def _check_attributes(self, element, title, description, tag):
        self.assertEqual(element.title, title)
        self.assertEqual(element.description, description)
        self.assertEqual(element.tag, tag)

This isn't super useful, because your check method is limited to this class. You could import it into another test class if you wanted to, but that's a little messy as far as separation of responsibility goes.

I typically try to have 1 test class per test file, corresponding to exactly one production class. Each 'test' is a method inside a test class. Then, if there's a function I want to run from a lot of test classes, I put it in a separate file that I call "test_helpers.py". You shouldn't make your test helpers inherit from TestCase. You can define a failure exception and raise it from your test helper method.

The following code would be split up over 5 separate files in the same directory. The file names are in comments. Notice that the class Blah lives in 'blah.py' and corresponds to a test class TestBlah in test_blah.py. That's where you test everything to do with Blah.

I stole the code for the FailureException in test_helpers.py directly from the source code for unittest.

#blah.py
class Blah(object):
    def __init__(self, title, description, tag):
        self.title = title
        self.description = description
        self.tag = tag

#test_blah.py
from test_helpers import check_attributes

class TestBlah(unittest.TestCase):
    def test_constructor(self):
        blah = Blah('Happy Gilmore', 'golf movie', 'ts')
        check_attributes(blah, 'Happy Gilmore', 'golf movie', 'ts')

#sub_blah.py
from blah import Blah

class SubBlah(Blah):
    def __init__(self, title, description, tag):
        super(SubBlah, self).__init__()
        self.different_attribute = "I'm Different!"

#test_sub_blah.py
from test_helpers import check_attributes

class TestSubBlah(unittest.TestCase):
    def test_constructor(self):
        sub_blah = SubBlah('Toy Story', 'kids movie', 'sb')
        check_attributes(blah, 'Toy Story', 'kids movie', 'sb')
        self.assertEqual("I'm Different!", sub_blah.different_attribute)

#test_helpers.py
import Exception

def check_attributes(element, title, description, tag):
    if not title == element.title:
            raise FailureException(msg or '%r != %r' % (title, element.title))
        if not description == element.description :
            raise FailureException(msg or '%r != %r' % (description, element.description))
        if not tag == element.tag:
            raise FailureException(msg or '%r != %r' % (tag, element.tag))

class FailureException(Exception):
    #pass here to make it a basic exception
    pass

    #If you  need custom code, you can override __init__
    #def __init__(self, message, errors):
    #
    #   super(FailureException, self).__init__(message)
Sign up to request clarification or add additional context in comments.

Comments

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.