Persist variable changes between tests in unittest? - python

How do I persist changes made within the same object inheriting from TestCase in unitttest?
from unittest import TestCase, main as unittest_main
class TestSimpleFoo(TestCase):
foo = 'bar'
def setUp(self):
pass
def test_a(self):
self.assertEqual(self.foo, 'bar')
self.foo = 'can'
def test_f(self):
self.assertEqual(self.foo, 'can')
if __name__ == '__main__':
unittest_main()
I.e.: I want those two tests above to pass

As some comments have echoed, structuring your tests in this manner is probably a design flaw in the tests themselves and you should consider restructuring them. However, if you want to do this and rely on the fact that the test runner you are using executes them in an alphabetical (seemingly) order then I suggest the following.
Similar to what #Matthias was saying but I would do one thing differently for the cases where you may decide to inherit from the class at a later date.
from unittest import TestCase, main as unittest_main
class TestSimpleFoo(TestCase):
foo = 'bar'
def setUp(self):
pass
def test_a(self):
self.assertEqual(self.__class__.foo, 'bar')
self.__class__.foo = 'can'
def test_f(self):
self.assertEqual(self.__class__.foo, 'can')
if __name__ == '__main__':
unittest_main()
The difference between this answer and #Matthias's answer you accepted is the explicit declaration of the class versus the lookup of said class reference.
TestSimpleFoo vs self.__class__
I prefer the dynamicness so I can inherit the tests later and run both test classes back to back and not have any cross over between the two. Because if you would choose to inherit from this class, explicitly naming the class reference would cause both test classes to run against that reference rather than their own respective classes.

I like your own answer for the simplicity of it, but if you want to keep distinct unit tests:
Apparently unittest runs separate tests with fresh instances of the TestCase. Well, just bind the objects to be persisted to something else but self. For example:
from unittest import TestCase, main as unittest_main
class TestSimpleFoo(TestCase):
def setUp(self):
pass
def test_a(self):
TestSimpleFoo.foo = 'can'
def test_f(self):
self.assertEqual(TestSimpleFoo.foo, 'can')
if __name__ == '__main__':
unittest_main()
You might be interesed in setUpClass and tearDownClass too:
https://docs.python.org/3/library/unittest.html#setupclass-and-teardownclass
Also take care about the execution order of your unit tests:
https://docs.python.org/2/library/unittest.html#unittest.TestLoader.sortTestMethodsUsing

Couldn't figure it out; so ended up hacking it out with multiple non test_ prefixed functions:
def test_password_credentials_grant(self):
for user in self.user_mocks:
self.register(user)
self.login(user)
self.access_token(user, self.assertEqual) # Ensures access_token is generated+valid
self.logout(user)
self.access_token(user, self.assertNotEqual) # Ensures access_token is now invalid
self.unregister(user)

Related

Unit Test with Mock and Multiple Functions

I cannot instantiate an object because it is an abstract class, so I have to use mocking in order to test my code.
I have been told this is best done by creating a new mock class.
class MockMyClass(MyClass):
def my_first_function(...):
The idea is that I then instantiate a MockMyClass object, where I can test private function in that.
I have read the python guide and researched other stack questions. Here, the theory behind mock has been well explained. Unfortunately, I am still lost with how mocking can be used in a large unittest for multiple functions. For instance:
If I have a class, from which other classes in the main code inherit functions from. This can take the form:
class SharedFunctions(AnotherClass):
first_function():
#do some important calculations to generate stuff.#
self.stuff = first_function_attribute_stuff
return returned_first_stuff
second_functions(returned_stuff)
returned_second_stuff = self.stuff + returned_first_stuff
return returned_second_stuff
and where the class SharedFunctions also inherits from another class (noting the abstract method) of the form:
class AnotherClass():
#abc.abstractmethod
def one_important_universal_function(...):
pass
I have tried to construct a unittest for the SharedFunctions piece of code.
This is what I have tried so far:
class MockSharedFunctions(SharedFunctions):
def first_function(...):
self.stuff = some value
returned_first_stuff = given some other value
return returned_first_stuff
def second_function
returned_second_stuff = another value.
return returned_second_stuff
class TestSharedFunctions(unittest.TestCase):
def test_first_function(self):
# insert code #
self.assertTrue(True)
def test_second_function(self):
# insert code #
self.assetEqual(output, expected)
self.assertTrue(True)
if __name__ == "__main__":
unittest.main()
Where insert code has been a number of various attempts to use mocking. However, I have not come across a clear example of how mock functions can be used to replace other functions, or a confirmation that this will work.
Thank you for any help.
A common issue is too over complicate the use of mocking functions. You can almost treat them like another class method. In your case, the abstractmethod decorator is probably generating the confusion.
This is something close to what you might need.
class MockSharedFunctions(SharedFunctions):
def one_important_universal_function(**args):
return 0
class TestSharedFunctions(unittest.TestCase):
def test_first_function(self):
mock = MockSharedFunctions()
mock_output = firstfunction(**args)
mock_stuff = mock.stuff
self.assertTrue(True)
self.assetEqual(mock_output, expected)
self.assetEqual(mock_stuff, expected)
def test_second_function(self):
mock = MockSharedFunctions()
mock.stuff = some_value
mock_output = second_function(**args)
self.assetEqual(mock_output, expected)
self.assertTrue(True)
if __name__ == "__main__":
unittest.main()
Here, in the MockSharedFunctions you are already inheriting SharedFunctions. As one_important_universal_function is an abstract method, it needs to be defined.

how to pass a class to be tested to an unit test class

I have a class and I need to test it
class ToBeTested():
def my_method():
pass
I have designed some unittests in python.
import unittest
class MyFirstUnitTest(unittest.TestCase):
def setUp(self):
# prepare some data
# run a method
# collect results
def test_one_assumption_about_results(self):
#self.assertEqual(...)
def test_another_assumption_about_results(self):
#self.assertEqual(...)
if __name__ == '__main__':
unittest.main()
I have designed this code looking at the examples.
Now I do not understand how to interface it the tesing class MyFirstUnitTest with the classe to be tested ToBeTested?
By inheritance?
class MyFirstUnitTest(unittest.TestCase,ToBeTested):
######
By creating a object of class ToBeTested as static member of
MyFirstUnitTest class definition?
class MyFirstUnitTest(unittest.TestCase):
mytestobj=ToBeTested()
def setUp(self):
By creating a object of class ToBeTested within each of the test
cases of MyFirstUnitTest class definition?
class MyFirstUnitTest(unittest.TestCase):
def setUp(self):
###
def test_one():
mytestobj=ToBeTested()
def test_two():
mytestobj=ToBeTested()
please suggest alternatives and why you would prefer any of them
There is a drawback to using inheritance and static member instead of creating a new object for every test: If tests change the state of the object, then the tests influence each other with their side effects. This gets even worse if the order of the test method calls are not guaranteed and changes (say, you rename a test and suddenly a different test case fails - these things have happened before!)
Additionally, having your test case inherit from the SUT (subject under test) means you only get to test one constructor.
I don't see any advantage to having the testcase inherit from the SUT, especially in python where there are no private members. If for some reason inheritance is necessary for the test (which sometimes IS the case), then having a seperate TestAdapter class that inherits and is instantiated by the test is the best practice.
There are other questions with answers which go more in depth:
https://softwareengineering.stackexchange.com/questions/366425/making-a-test-fixture-inherit-from-the-sut-class
https://softwareengineering.stackexchange.com/questions/154144/how-to-define-implementation-details
You can create an instance of your class(es) in your setup if it will not have to be reinstantiated.
And if you have to create a new instance in every test then just create a new instance in every test.

How should a Python (unittest) superclass method reference a variable in its calling subclass?

I am simply not experienced enough in Python OO programming to know how this is done: If I have several classes that are subclasses of a unittest.TestCase subclass. How should the superclass' methods reference variables of the subclasses when the latter call these methods? Let me try to illustrate it with this, probably wrong, example:
import unittest
class TestSuper(unittest.TestCase):
def test_method(self):
# do something, e.g.
pass
class TestSub1(TestSuper):
def setUp(self):
self.some_parameter = 1
class TestSub2(TestSuper):
def setUp(self):
self.some_parameter = 2
if __name__ == '__main__':
unittest.main()
Now, I cannot figure out how to correcty reference TestSub1.parameter or TestSub2.parameter, respectively, when TestSuper.test_method is called from the subclasses.
I am inspired by https://stackoverflow.com/a/25695512/865169, but here I am trying achieve having multiple test cases that do the same but only differ in their set-up. I can of course achieve all this by just copy-pasting my test case definitions, but I find that bad coding practice.
Just use self.some_parameter; self is always bound to the right instance here.
However, take into account that unittest.main() will run test_method on *all three test cases (the baseclass included), so you'll have to provide a default value for some_parameter on the base class.
If you don't want TestSuper to be seen as a test case, don't inherit from unittest.TestCase. Use it as a mix-in instead:
import unittest
class TestMixin(object):
def test_method(self):
# do something, e.g.
pass
class TestSub1(unittest.TestCase, TestMixin):
def setUp(self):
self.some_parameter = 1
class TestSub2(unittest.TestCase, TestMixin):
def setUp(self):
self.some_parameter = 2
if __name__ == '__main__':
unittest.main()
Now unittest.main() will only find two test cases (TestSub1 and TestSub2) and run test_method only on those cases.

How to pass a function I want to check as a parameter to unittest.TestCase in Python 3.x

For example, I have functions that are working with strings. And I would like to create an unittest, which is checking the functions. Sometimes, tests are identical, so I was thinking for creating BaseCase, which is do similar jobs for all functions. And function is an argument for this BaseCase. How can I do it? I came up with something like this...
class BaseTestCase (unittest.TestCase):
def setUp(self):
self.newMethod = None
def testMethod (self):
if self.newMethod:
self.assertEqual (1, self.newMethod())
def someF():
return 1
class SomeTestCase (BaseTestCase):
def setUp(self):
self.newMethod = someF
if __name__ == "__main__":
unittest.main()
It is working as I need, but it fire one extra test (with all ok in it) for test method. Is it possible to do the same job via _init__ and super()?

How can I add a test method to a group of Django TestCase-derived classes?

I have a group of test cases that all should have exactly the same test done, along the lines of "Does method x return the name of an existing file?"
I thought that the best way to do it would be a base class deriving from TestCase that they all share, and simply add the test to that class. Unfortunately, the testing framework still tries to run the test for the base class, where it doesn't make sense.
class SharedTest(TestCase):
def x(self):
...do test...
class OneTestCase(SharedTest):
...my tests are performed, and 'SharedTest.x()'...
I tried to hack in a check to simply skip the test if it's called on an object of the base class rather than a derived class like this:
class SharedTest(TestCase):
def x(self):
if type(self) != type(SharedTest()):
...do test...
else:
pass
but got this error:
ValueError: no such test method in <class 'tests.SharedTest'>: runTest
First, I'd like any elegant suggestions for doing this. Second, though I don't really want to use the type() hack, I would like to understand why it's not working.
You could use a mixin by taking advantage that the test runner only runs tests inheriting from unittest.TestCase (which Django's TestCase inherits from.) For example:
class SharedTestMixin(object):
# This class will not be executed by the test runner (it inherits from object, not unittest.TestCase.
# If it did, assertEquals would fail , as it is not a method that exists in `object`
def test_common(self):
self.assertEquals(1, 1)
class TestOne(TestCase, SharedTestMixin):
def test_something(self):
pass
# test_common is also run
class TestTwo(TestCase, SharedTestMixin):
def test_another_thing(self):
pass
# test_common is also run
For more information on why this works do a search for python method resolution order and multiple inheritance.
I faced a similar problem. I couldn't prevent the test method in the base class being executed but I ensured that it did not exercise any actual code. I did this by checking for an attribute and returning immediately if it was set. This attribute was only set for the Base class and hence the tests ran everywhere else but the base class.
class SharedTest(TestCase):
def setUp(self):
self.do_not_run = True
def test_foo(self):
if getattr(self, 'do_not_run', False):
return
# Rest of the test body.
class OneTestCase(SharedTest):
def setUp(self):
super(OneTestCase, self).setUp()
self.do_not_run = False
This is a bit of a hack. There is probably a better way to do this but I am not sure how.
Update
As sdolan says a mixin is the right way. Why didn't I see that before?
Update 2
(After reading comments) It would be nice if (1) the superclass method could avoid the hackish if getattr(self, 'do_not_run', False): check; (2) if the number of tests were counted accurately.
There is a possible way to do this. Django picks up and executes all test classes in tests, be it tests.py or a package with that name. If the test superclass is declared outside the tests module then this won't happen. It can still be inherited by test classes. For instance SharedTest can be located in app.utils and then used by the test cases. This would be a cleaner version of the above solution.
# module app.utils.test
class SharedTest(TestCase):
def test_foo(self):
# Rest of the test body.
# module app.tests
from app.utils import test
class OneTestCase(test.SharedTest):
...

Categories

Resources