python unittest methods - python

Can I call a test method from within the test class in python? For example:
class Test(unittest.TestCase):
def setUp(self):
#do stuff
def test1(self):
self.test2()
def test2(self):
#do stuff
update: I forgot the other half of my question. Will setup or teardown be called only after the method that the tester calls? Or will it get called between test1 entering and after calling test2 from test1?

This is pretty much a Do Not Do That. If you want tests run in a specific order define a runTest method and do not name your methods test....
class Test_Some_Condition( unittest.TestCase ):
def setUp( self ):
...
def runTest( self ):
step1()
step2()
step3()
def tearDown( self ):
...
This will run the steps in order with one (1) setUp and one (1) tearDown. No mystery.

Try running the following code:
import unittest
class Test(unittest.TestCase):
def setUp(self):
print 'Setting Up'
def test1(self):
print 'In test1'
self.test2()
def test2(self):
print 'In test2'
def tearDown(self):
print 'Tearing Down'
if __name__ == '__main__':
unittest.main()
And the results is:
Setting Up
In test1
In test2
Tearing Down
.Setting Up
In test2
Tearing Down
.
----------------------------------------------------------------------
Ran 2 tests in 0.000s
OK
Now you see, setUp get called before a test method get called by unittest, and tearDown is called after the call.

All methods whose name begins with the string 'test' are considered unit tests (i.e. they get run when you call unittest.main()). So you can call methods from within the Test class, but you should name it something that does not start with the string 'test' unless you want it to be also run as a unit test.

sure, why not -- however that means test2 will be called twice -- once by test1 and then again as its own test, since all functions named test will be called.

Yes to both:
setUp will be called between each test
test2 will be called twice.
If you would like to call a function inside a test, then omit the test prefix.

Related

pytest is not running any tests

My tests are in the following folder structure. Though I have also placed a sample test in the root, which doesn't work either. I get no tests ran in 6.08s
root/
test/
integrations/
test_sample.py
__init__.py
__init__.py
I have tried using the command pytest by itself as well as specifying the test location pytest ./test/integrations/test_sample.py
I've been using a class to define multiple tests, but simple functions aren't running either.
Class:
class TestClass:
def add(self):
pass
Function:
def add():
pass
You need to write a test as function with a name beginning with test. See pytest's docs: test-discovery.
In this test or function:
instantiate your class
and run the class' method or function
import pytest
# this class will be tested
class ClassUnderTest:
def add(self):
return "it ran"
# This test will run because its name begins with "test"
def test_add():
cls = ClassUnderTest()
assert cls.add() == "it ran"
# This won't run because its name does not begin with "test"
def run_add():
cls = ClassUnderTest()
assert cls.add() == "it ran"
# ===== 1 passed in 0.05s =====
Methods name should start with test_. (inside class or out) is this what you're missing?

How can you mock a variable inside of python class?

I have a Python class that I'm trying mock a certain variable in my unit test.
Excerpt of my Python class:
class something:
def __init__(self):
self._commandline = 'dir'
def run_function(self):
pass
In my unit test I am trying to set the class variable _commandline to something like "dirx" so that when I call run_function() that uses subprocess.run it'll fail and throw a subprocess.CalledProcessError so that I can test my assert.
This is my first time doing TDD please advice if there is a better way of doing this.
Thanks in advance!
Just re-assign the _commandLine variable.
E.g.
something.py:
class Something:
def __init__(self):
self._commandline = 'dir'
def run_function(self):
print(self._commandline)
pass
test_something.py:
import unittest
from something import Something
class TestSomething(unittest.TestCase):
def test_run_function(self):
instance = Something()
instance._commandline = 'dirx'
instance.run_function()
if __name__ == '__main__':
unittest.main()
test result:
dirx
.
----------------------------------------------------------------------
Ran 1 test in 0.000s
OK

Do setUp and tearDown methods run for each method or at the beginning and at the end of TestCase

Do test methods which are members of the same TestCase affect each other ?
In python unittest I try to understand that if i change a variable in a test method, does the variable change in other test method . Or do setUp and tearDown methods run for each method and so variables set up again for each method ?
I mean
AsdfTestCase(unittest.TestCase):
def setUp(self):
self.dict = {
'str': 'asdf',
'int': 10
}
def tearDown(self):
del self.dict
def test_asdf_1(self):
self.dict['str'] = 'test string'
def test_asdf_2(self):
print(self.dict)
So I am asking which output test_asdf_2() will print
'asdf' or 'test_string'
Yes, setUp and tearDown run before EACH test (i.e. function starting with 'test' in the name) in the testcase class. Consider this example:
# in file testmodule
import unittest
class AsdfTestCase(unittest.TestCase):
def setUp(self) : print('setUp called')
def tearDown(self) : print('tearDown called')
def test_asdf_1(self): print( 'test1 called' )
def test_asdf_2(self): print( 'test2 called' )
Calling it from the command line:
$ python3 -m unittest -v testmodule
test_asdf_1 (testmodule.AsdfTestCase) ... setUp called
test1 called
tearDown called
ok
test_asdf_2 (testmodule.AsdfTestCase) ... setUp called
test2 called
tearDown called
ok
----------------------------------------------------------------------
Ran 2 tests in 0.000s
OK
(therefore, yes, in your example, it would pring 'asdf' since the setUp is re-executed, overwriting the changes caused by test 2)
Each Test Case is real in isolation. The setup method is ran before each Test Case and the teardown is ran after each Test Case.
So to answer your question, if you change a variable in your Test Case it will not affect other Test Cases.
You were on the right path by writing test code. It's always a better learning experience when you do it yourself. However, here's your answer.
Example code:
import unittest
class AsdfTest(unittest.TestCase):
def setUp(self):
print "Set Up"
self.dict = {
'str': 'asdf',
'int': 10
}
def tearDown(self):
print "Tear Down"
self.dict = {}
def test_asdf_1(self):
print "Test 1"
self.dict['str'] = 'test string'
print self.dict
def test_asdf_2(self):
print "Test 2"
print self.dict
if __name__ == '__main__':
unittest.main()
Output:
Set Up
Test 1
{'str': 'test string'}
Tear Down
.Set Up
Test 2
{}
Tear Down
.
----------------------------------------------------------------------
Ran 2 tests in 0.000s
OK
You can see that the set up method is run before each test. Then the tear down method is run after each test.

Python unit tests run function after all test

I need to test smth on python via ssh. I don't want to make ssh connection for every test, because it is to long, I have written this:
class TestCase(unittest.TestCase):
client = None
def setUp(self):
if not hasattr(self.__class__, 'client') or self.__class__.client is None:
self.__class__.client = paramiko.SSHClient()
self.__class__.client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
self.__class__.client.connect(hostname=consts.get_host(), port=consts.get_port(), username=consts.get_user(),
password=consts.get_password())
def test_a(self):
pass
def test_b(self):
pass
def test_c(self):
pass
def disconnect(self):
self.__class__.client.close()
and my runner
if __name__ == '__main__':
suite = unittest.TestSuite((
unittest.makeSuite(TestCase),
))
result = unittest.TextTestRunner().run(suite)
TestCase.disconnect()
sys.exit(not result.wasSuccessful())
In this version I get error TypeError: unbound method disconnect() must be called with TestCase instance as first argument (got nothing instead). So how i can call disconnect after all tests pass?
With best regards.
You should use setUpClass and tearDownClass instead, if you want to keep the same connection for all tests. You'll also need to make the disconnect method static, so it belongs to the class and not an instance of the class.
class TestCase(unittest.TestCase):
def setUpClass(cls):
cls.connection = <your connection setup>
#staticmethod
def disconnect():
... disconnect TestCase.connection
def tearDownClass(cls):
cls.disconnect()
you can do it by defining startTestRun,stopTestRun of unittest.TestResult class. setUpClass and tearDownClass are running per test class(per test file) so if you have multiple files this methods will run for each one.
by adding following code to my tests/__init__.py i managed to achieve it. this code runs only once for all tests(regardless of number of test classes and test files).
def startTestRun(self):
"""
https://docs.python.org/3/library/unittest.html#unittest.TestResult.startTestRun
Called once before any tests are executed.
:return:
"""
DockerCompose().start()
setattr(unittest.TestResult, 'startTestRun', startTestRun)
def stopTestRun(self):
"""
https://docs.python.org/3/library/unittest.html#unittest.TestResult.stopTestRun
Called once after all tests are executed.
:return:
"""
DockerCompose().compose.stop()
setattr(unittest.TestResult, 'stopTestRun', stopTestRun)
There seems to be a simple solution for the basic (beginner's) case:
def tmain():
setup()
unittest.main(verbosity=1, exit=False)
clean()
The trick is "exit=False" which lets the function tmain run until the end.
setup() and clean() can be any functions to do what the name implies.

Testing methods each with a different setup/teardown

I'm testing a class, with many test methods. However, each method has a unique context. I then write my code as following:
class TestSomeClass(unittest.TestCase):
def test_a():
with a_context() as c:
pass
def test_b():
with b_context() as c:
pass
def test_c():
with c_context() as c:
pass
However, the context managers are irrelevant to the test case, and produce temporary files. So as to not pollute the file system when the test fails, I would like to use each context manager in a setup/teardown scenario.
I've looked at nose's with_setup, but the docs say that is meant for functions only, not methods. Another way is to move the test methods to separate classes each with a setup/teardown function. What's a good way to do this?
First of all, I'm not sure why what you have isn't working. I wrote some test code, and it shows that the exit code always gets called, under the unittest.main() execution environment. (Note, I did not test nose, so maybe that's why I couldn't replicate your failure.) Maybe your context manager is broken?
Here's my test:
import unittest
import contextlib
import sys
#contextlib.contextmanager
def context_mgr():
print "setting up context"
try:
yield
finally:
print "tearing down context"
class TestSomeClass(unittest.TestCase):
def test_normal(self):
with context_mgr() as c:
print "normal task"
def test_raise(self):
with context_mgr() as c:
print "raise task"
raise RuntimeError
def test_exit(self):
with context_mgr() as c:
print "exit task"
sys.exit(1)
if __name__ == '__main__':
unittest.main()
By running that with $ python test_test.py I see tearing down context for all 3 tests.
Anyway, to answer your question, if you want a separate setup and teardown for each test, then you need to put each test in its own class. You can set up a parent class to do most of the work for you, so there isn't too much extra boilerplate:
class TestClassParent(unittest.TestCase):
context_guard = context_mgr()
def setUp(self):
#do common setup tasks here
self.c = self.context_guard.__enter__()
def tearDown(self):
#do common teardown tasks here
self.context_guard.__exit__(None,None,None)
class TestA(TestClassParent):
context_guard = context_mgr('A')
def test_normal(self):
print "task A"
class TestB(TestClassParent):
context_guard = context_mgr('B')
def test_normal(self):
print "task B"
This produces the output:
$ python test_test.py
setting up context: A
task A
tearing down context: A
.setting up context: B
task B
tearing down context: B
.
----------------------------------------------------------------------
Ran 2 tests in 0.000s
OK

Categories