Avoid converting functions to methods in a class

S

Steven D'Aprano

I have a convention when writing unit tests to put the target of the test
into a class attribute, as follows:

class MyTest(unittest.TestCase):
target = mymodule.someclass

def test_spam(self):
"""Test that someclass has a spam attribute."""
self.failUnless(hasattr(self.target, 'spam'))


It works well until I write a test for stand-alone functions:

class AnotherTest(unittest.TestCase):
target = mymodule.function

def test_foo(self):
self.assertEquals(self.target('a', 'b'), 'foo')

The problem is that target is turned into a method of my test class, not
a standalone function, and I get errors like:

TypeError: function() takes exactly 2 arguments (3 given)

The solution I currently use is to drop the target attribute in this
class, and just refer to mymodule.function in each individual test. I
don't like this solution because it violates Once And Only Once: if the
function changes name, I have to make many edits to the test suite rather
than just one.

Are there any better solutions?
 
A

Arnaud Delobelle

I have a convention when writing unit tests to put the target of the test
into a class attribute, as follows:

class MyTest(unittest.TestCase):
    target = mymodule.someclass

    def test_spam(self):
        """Test that someclass has a spam attribute."""
        self.failUnless(hasattr(self.target, 'spam'))

It works well until I write a test for stand-alone functions:

class AnotherTest(unittest.TestCase):
    target = mymodule.function

    def test_foo(self):
        self.assertEquals(self.target('a', 'b'), 'foo')

The problem is that target is turned into a method of my test class, not
a standalone function, and I get errors like:

TypeError: function() takes exactly 2 arguments (3 given)

The solution I currently use is to drop the target attribute in this
class, and just refer to mymodule.function in each individual test. I
don't like this solution because it violates Once And Only Once: if the
function changes name, I have to make many edits to the test suite rather
than just one.

Are there any better solutions?

Why not define target in the TestCase.setUp() method?

class AnotherTest(unittest.TestCase):

def setUp(self):
self.target = mymodule.function

def test_foo(self):
self.assertEquals(self.target('a', 'b'), 'foo')

--
Arnaud



class
 
J

Jean-Michel Pichavant

Steven said:
I have a convention when writing unit tests to put the target of the test
into a class attribute, as follows:

class MyTest(unittest.TestCase):
target = mymodule.someclass

def test_spam(self):
"""Test that someclass has a spam attribute."""
self.failUnless(hasattr(self.target, 'spam'))


It works well until I write a test for stand-alone functions:

class AnotherTest(unittest.TestCase):
target = mymodule.function

def test_foo(self):
self.assertEquals(self.target('a', 'b'), 'foo')

The problem is that target is turned into a method of my test class, not
a standalone function, and I get errors like:

TypeError: function() takes exactly 2 arguments (3 given)

The solution I currently use is to drop the target attribute in this
class, and just refer to mymodule.function in each individual test. I
don't like this solution because it violates Once And Only Once: if the
function changes name, I have to make many edits to the test suite rather
than just one.

Are there any better solutions?

It looks like it works when declaring foo as static:

import unittest

def foo(a,b):
return 'fooo'

class AnotherTest(unittest.TestCase):
target = staticmethod(foo)

def test_foo(self):
self.assertEquals(self.target('a', 'b'), 'foo')

def runTest(self):
self.test_foo()

AnotherTest().runTest()
....AssertionError: 'fooo' != 'foo'

JM
 
D

Daniel Fetchinson

I have a convention when writing unit tests to put the target of the test
into a class attribute, as follows:

class MyTest(unittest.TestCase):
target = mymodule.someclass

def test_spam(self):
"""Test that someclass has a spam attribute."""
self.failUnless(hasattr(self.target, 'spam'))


It works well until I write a test for stand-alone functions:

class AnotherTest(unittest.TestCase):
target = mymodule.function

def test_foo(self):
self.assertEquals(self.target('a', 'b'), 'foo')

The problem is that target is turned into a method of my test class, not
a standalone function, and I get errors like:

TypeError: function() takes exactly 2 arguments (3 given)

The solution I currently use is to drop the target attribute in this
class, and just refer to mymodule.function in each individual test. I
don't like this solution because it violates Once And Only Once: if the
function changes name, I have to make many edits to the test suite rather
than just one.

Isn't staticmethod the trick you need?

HTH,
Daniel
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,581
Members
45,056
Latest member
GlycogenSupporthealth

Latest Threads

Top