2

If I have tests for simple functions, fun1 and fun2, which need some arguments:

class TestOne(unittest.TestCase):
    def test_func1(self):
        a = 0
        b = 1
        c = 2
        self.assertEquals(c, fun1(a,b))

    def test_fun2(self):
        d = 0
        e = 1
        f = 2
        self.assertEquals(f, fun2(d,e))

and a test for a third function, which need the output of fun1 and fun2 as input

class TestTwo(unittest.TestCase):

    def test_fun3(self):
        a = 0
        b = 1
        d = 0
        e = 1
        g = 3
        self.assertEquals(g, fun3(fun1(a,b), fun2(d,e)))

what is the best way to avoid having to re-write the arguments of the first functions?

4
  • 2
    Can I ask why you want to use the results of fun1 and fun2 in your unit test for fun3? Why not just put the expected results of fun1 and fun2 into the test for fun3? In other words, if fun1(0, 1) returns 5 and fun2(0, 1) returns 6, write your test for fun3 as fun3(5, 6). Commented Jul 29, 2013 at 19:47
  • Because, aparat from return value, those functions might have side effects. Commented Jul 29, 2013 at 19:49
  • @MarkHildreth , because I test with many values over fun1 and fun2 and in some case the difference of value is in the last decimals, but I have the same question, is a good idea use functions as input in a unit test ? Commented Jul 29, 2013 at 20:18
  • 1
    @JuanPablo: The main issue you're going to have is that if fun1 or fun2 change logic, your tests for fun3 may now fail (even though fun3 is still correct). Likewise, a test for fun3 might pass even though fun3 is implemented incorrectly because fun2 is actually implemented wrong. Your tests might also run slower, and be more likely to fail. If your issue is decimal places, you should learn to set up a variable with the problematic decimals. In addition to making your tests less reliant on other functions, it makes the test more clear as to what you're testing. Commented Jul 29, 2013 at 20:26

4 Answers 4

2

You have a few of options:

  1. I'm adding this one at the top as every other answer seems to want to use inheritance. If this is the case and you only want to set up the values before each test section (versus each test with setUp), use setUpClass:

    from unittest import TestCase
    class BaseTest(TestCase):
      def setUpClass(cls):
        cls.a = 0
        cls.b = 1
        cls.c = 2
    
    class TestOne(BaseTest):
      def test_func1(self):
        self.assertEquals(self.c, func1(self.a, self.b))
    
  2. Use setUp. This is probably not the best solution if you're going to be changing the parameters often. But you can also define the setup in a base class and use inheritance (as others have suggested) .

    from unittest import TestCase
    class TestingSomething(TestCase):
      def setUp(self):
        self.parameters = [(0, 1), ]
    
      def test_func1(self):
        params = self.parameters[0]
        res = func1(*params)
        self.assertEquals(2, res)
    
  3. Define helper functions.

    from unittest import TestCase
    class TestingSomething(TestCase):
    
      def param_set_one(self):
        return (0, 1), 2
    
      def test_func1(self):
        params, expected = self.param_set_one()
        res = self.obj.func1(*params)
        self.assertEquals(expected, res)
    
  4. Perhaps a more specific answer to your question could be use use a more specific helper function:

    from unittest import TestCase
    class TestingSomething(TestCase):
      def setUp(self):
        self.obj = TestOne()
    
      def param_set(self):
        return (0, 1)
    
      def get_func1(self):
        return self.obj.func1(*self.param_set())
    
      def get_func2(self):
        return self.obj.func2(*self.param_set())
    
      def test_func1(self):
        params = self.param_set()
        res = self.obj.func1(*params)
        self.assertEquals(2, res)
      [...]
      def test_func3(self):
        retval_func1 = self.get_func1_retval()
        retval_func2 = self.get_func2_retval()
        self.assertEqual(3, func3(retval_func1, retval_func2))
    

    If you want your tests to be in separate classes, just declare the helper function outside of your test cases.

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

Comments

1
class Base(unittest.TestCase):
    fun1_val = fun1(a=0, b=1)
    fun2_val = fun2(d=0, e=1)

class TestOne(Base):
    def test_func1(self):
        c = 2
        self.assertEquals(c, self.fun1_val)

    def test_fun2(self):
        f = 2
        self.assertEquals(f, self.fun2_val)

class TestTwo(Base):
    def test_fun3(self):
        g = 3
        self.assertEquals(g, fun3(self.fun1_val, self.fun2_val))        

By making fun1_val and fun2_val class attributes of Base, they will be computed only once at the time Base is defined. The result can later be accessed in TestOne and TestTwo.

3 Comments

the Base class need the __init__ ?
Base does not need an __init__. It will inherit unittest.TestCase.__init__, which should work just fine.
In this case, does the Base class really need to be a TestCase object? In fact, why are you using a class at all? If this is what is desired, just store the values in a list or a dict. Even better, declare setUpClass and inherit from that.
0

I believe you can also create another class. I've seen this done, but I haven't actually done it before. If people know that this works, please leave a comment :) while I test it out myself:

class Tests(unittest.TestCase):
    def __init__(self):
        self.a = 0
        self.b = 1
        self.c = 2

class TestOne(Tests):
    def test_func1(self):
        self.a
        self.b
        self.c

class TestTwo(Tests):
    def test_fun3(self):
        self.a
        self.b
        self.c

UPDATE: By changing self.a~c in class Tests(), test_func1 & test_func3 in TestOne & TestTwo print out appropriate values.

2 Comments

This works because both TestOne and TestTwo inherit from Tests, thus the Tests.__init__ is called for each of those two tests resulting in both of them having a, b and c defined.
Shouldn't you use setUpClass or setUp instead of __init__?
-1
from functools import partial

f1 = partial(fun1, a, b)
f2 = partial(fun2, d, e)

Calling (ref):

f1()
f2()

Or in your case:

f1 = partial(fun1, 0, 1)
f2 = partial(fun2, 0, 1)

Example:

In [1]: from functools import partial

In [2]: def fun1(a, b):
   ...:     return a + b
   ...: 

In [3]: f1 = partial(fun1, 0 ,1)

In [4]: f1()
Out[4]: 1

1 Comment

@Radio-, what is the best way to avoid having to re-write the arguments of the first functions? It allows you to avoid re-writing arguments - solves the problem the asker had. Memoizing the return value is not always the best choice as functions might have side effects.

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.