Avoid converting functions to methods in a class

Discussion in 'Python' started by Steven D'Aprano, Feb 20, 2010.

  1. 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?


    --
    Steven
     
    Steven D'Aprano, Feb 20, 2010
    #1
    1. Advertising

  2. On 20 Feb, 03:33, Steven D'Aprano <st...@REMOVE-THIS-
    cybersource.com.au> wrote:
    > 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?
    >
    > --
    > Steven


    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
    --
    Arnaud
     
    Arnaud Delobelle, Feb 20, 2010
    #2
    1. Advertising

  3. Steven D'Aprano wrote:
    > 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
     
    Jean-Michel Pichavant, Feb 23, 2010
    #3
  4. > 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


    --
    Psss, psss, put it down! - http://www.cafepress.com/putitdown
     
    Daniel Fetchinson, Feb 23, 2010
    #4
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Alexander Malkis
    Replies:
    8
    Views:
    549
    Alexander Malkis
    Apr 14, 2004
  2. Oliver Wong
    Replies:
    14
    Views:
    1,677
    Chris Uppal
    Jun 13, 2006
  3. Roger23
    Replies:
    2
    Views:
    1,037
    Roger23
    Oct 12, 2006
  4. Oltmans
    Replies:
    6
    Views:
    385
    Terry Reedy
    Mar 11, 2009
  5. Kenneth McDonald
    Replies:
    5
    Views:
    373
    Kenneth McDonald
    Sep 26, 2008
Loading...

Share This Page