Raises an AssertionError exception if the variable test is false.
test = 0
data = "assertion error"
try:
    assert test,data
except AssertionError:
    print data
finally:
    print "the end"
If it is only the assert statement part, you can substitute it by writing as follows.
if __debug__:
  if not test
    raise AssertionError, data
somedata = 1
#Tuple the exceptions you want to catch.
fatal_exceptions = (KeyboardInterrupt, MemoryError)
try:
    assert somedata
except fatal_exceptions, inst:  #You can receive the contents of the exception with the argument inst.
    print type(inst)    #Show exception type
    print inst          #Show the contents of the exception
    raise
#Catch all other exceptions
except Exception, inst:
    print type(inst)    #Show exception type
    print inst          #Show the contents of the exception
finally:
    print "the end"
UnitTest Slightly modified and added examples from the official tutorial.
import random
import unittest
class TestSequenceFunctions(unittest.TestCase):
    #Initialization process called every time
    #In addition to this, there is a method called after executing the test etc.
    def setUp(self):
        self.seq = range(10)
    #Describe the method name starting with test.
    def test_shuffle(self):
        random.shuffle(self.seq)
        self.seq.sort()
        #Check that the two arguments are equal.
        #Checking for inequality is assertNotEqual()You can do it with.
        self.assertEqual(self.seq, range(10))
        #Check that an exception will occur.
        # assertRaises(exception, callable, *args, **kwds)
        #Pass args and kwds to the function of the second argument and check that the exception specified by the first argument occurs.
        self.assertRaises(TypeError, random.shuffle, (1,2,3))
    def test_choice(self):
        element = random.choice(self.seq)
        #Check that the value of the argument is True.
        # bool(element)Equivalent to is True
        self.assertTrue(element in self.seq)
    def test_sample(self):
        #If only the exception argument is passed, the context manager is returned.
        #You can write the code to be tested inline.
        with self.assertRaises(ValueError):
            random.sample(self.seq, 20)
        for element in random.sample(self.seq, 5):
            self.assertTrue(element in self.seq)
if __name__ == '__main__':
    
    # main()Can be executed with.
    unittest.main()
    #Get tests to run individually.
    _test_choice = TestSequenceFunctions('test_choice')
    _test_sample = TestSequenceFunctions('test_sample')
    #It can be registered in the test suite and executed collectively by the runner.
    TestSuite = unittest.TestSuite()
    TestSuite.addTest(_test_choice)
    TestSuite.addTest(_test_sample)
    runner = unittest.TextTestRunner()
    runner.run(TestSuite)
    #You can get test functions collectively with the loader.
    suite = unittest.TestLoader().loadTestsFromTestCase(TestSequenceFunctions)
    unittest.TextTestRunner(verbosity=2).run(suite)
traceback The stack is the memory area where the program is currently running. A stack trace is a record of the execution status (function name, calling function name, line, statement, file name) of the program in the memory area, and this is an object in a script language such as Python. It is provided.
First, stack trace information can be obtained from sys.exc_info ().
exc_type, exc_value, exc_traceback = sys.exc_info()
Using these three variables as arguments, traceback.print_tb () and traceback.print_exception () display the information.
However, if you use traceback.print_exc () below, you can omit the variable acquisition from sys.exc_info (), and you can also display the type and contents, which is convenient. Basically you can use this.
import sys
import traceback
def somework():
    try:
        print a #Use undefined variables
    except Exception:
        print "error"
        traceback.print_exc(file=sys.stdout)
    finally:
        print "the end"
if __name__ == '__main__':
    somework()
Output result The module name, line, function name, cause statement, and cause error message are output.
error
Traceback (most recent call last):
  File "/Users/test.py", line 8, in somework
    print a
NameError: global name 'a' is not defined
the end
This is the output when traceback is not written. Nothing is output, just passing the exception.
error
the end
Next, a method of acquiring stack trace information as a list including tuples is shown. Here is also an example of getting a variable from sys.exc_info (). (Because it is used as an argument)
import sys
import traceback
def somework():
    try:
        print a #Use undefined variables
    except Exception:
        print "error"
        exc_type, exc_value, exc_traceback = sys.exc_info()
        print traceback.extract_tb(exc_traceback) #Get only current information
        print traceback.extract_stack() #Get a tuple containing the caller's function information
        #Call this if you just want to receive it as a list instead of a tuple and make it easier to display.
        traceback.format_tb(exc_traceback)
        traceback.format_stack()
        print "the end"
if __name__ == '__main__':
    somework()
nosetest
I referred to "Python Professional Programming".
installation of nose
pip install nose
Class to be tested This class simply adds or subtracts numbers to your bank account.
# coding: UTF-8
class NotEnoughFundsException(Exception):
    pass
class BankAccount(object):
    def __init__(self):
        self._balance = 0
    def deposit(self, amount):
        self.balance += amount
    def withdraw(self, amount):
        self.balance -= amount
    def get_balance(self):
        return self._balance
    def set_balance(self, value):
        if value < 0:
            raise NotEnoughFundsException
        self._balance = value
    #Prepare a wrapper so that you can use getters and setters.
    #to balance=Or+These functions will be called automatically by accessing with.
    balance = property(get_balance, set_balance)
Write code to test with nose. Preparing a fixed value for testing, such as 100 or 0, is called a data fixture.
# coding: UTF-8
import unittest
class BankAccountTest(unittest.TestCase):
    def _getTarget(self):
        from bankaccount import BankAccount
        return BankAccount
    #Create an instance to be tested.
    def _makeOne(self, *args, **kwargs):
        return self._getTarget()(*args, **kwargs)
    def test_construct(self):
        target = self._makeOne()
        self.assertEqual(target._balance, 0)
    def test_deposit(self):
        target = self._makeOne()
        target.deposit(100)
        self.assertEqual(target._balance, 100)
    def test_withdraw(self):
        target = self._makeOne()
        target._balance = 100
        target.withdraw(20)
        self.assertEqual(target._balance, 80)
    def test_get_blance(self):
        target = self._makeOne()
        target._balance = 500
        self.assertEqual(target.get_balance(), 500)
    def test_set_balance_not_enough_funds(self):
        target = self._makeOne()
        from bankaccount import NotEnoughFundsException
        try:
            target.set_balance(-1)
            self.fail()
        except NotEnoughFundsException:
            pass
Place the above two in the same directory and execute nose in that directory.
nosetest
.....
----------------------------------------------------------------------
Ran 5 tests in 0.004s
OK
pip install coverage
# nosetests -v --with-coverage
test_construct (test_bankaccount.BankAccountTest) ... ok
test_deposit (test_bankaccount.BankAccountTest) ... ok
test_get_blance (test_bankaccount.BankAccountTest) ... ok
test_set_balance_not_enough_funds (test_bankaccount.BankAccountTest) ... ok
test_withdraw (test_bankaccount.BankAccountTest) ... ok
Name          Stmts   Miss  Cover   Missing
-------------------------------------------
bankaccount      16      0   100%
----------------------------------------------------------------------
Ran 5 tests in 0.006s
OK
Easy-to-read coverage is output.
Output in XUNIT format with the "--with-xunit" option.
# nosetests -v -w . --with-coverage --with-xunit
test_construct (test_bankaccount.BankAccountTest) ... ok
test_deposit (test_bankaccount.BankAccountTest) ... ok
test_get_blance (test_bankaccount.BankAccountTest) ... ok
test_set_balance_not_enough_funds (test_bankaccount.BankAccountTest) ... ok
test_withdraw (test_bankaccount.BankAccountTest) ... ok
----------------------------------------------------------------------
XML: nosetests.xml
Name          Stmts   Miss  Cover   Missing
-------------------------------------------
bankaccount      16      0   100%
----------------------------------------------------------------------
Ran 5 tests in 0.006s
OK
Output in XML so that it can be read by jenkins.
coverage xml
mock
Class to be tested testモジュールのTest.py
# coding: UTF-8
class Widget(object):
    def __init__(self):
        self.value = 10
    def Additional(self, add):
        self.value += add
        return self.value
Test code
from mock import Mock
from test import Test
def mock_value(value):
    return 20 + value
if __name__ == '__main__':
    #Replace the function with a mock that returns 100 fixedly.
    Test.Widget.Additional = Mock(return_value=100)
    w = Test.Widget()
    print w.Additional(1)
    #If you want to do some calculation instead of a fixed value, side_Pass a dummy function in effect.
    Test.Widget.Additional = Mock(side_effect=mock_value)
    print w.Additional(1)
100
21
from mock import Mock
from test import Test
def mock_value(value):
    return 20 + value
if __name__ == '__main__':
    #Replace the class itself.
    Test.Widget = Mock()
    #The value returned by the function is fixed.
    Test.Widget.return_value.Additional.return_value = 10
    w = Test.Widget()
    print w.Additional(1)
    #Swap functions
    Test.Widget.return_value.Additional = mock_value
    print w.Additional(1)
patch Replaces a mock object running a function with a real object.
# coding: UTF-8
from mock import patch
#Specify the method and return value to replace only while this function is executing
@patch("Test.Widget.Additional", return_value=10)
def test_func(m): 
    import Test
    w = Test.Widget()
    print w.Additional(1)
    assert w.Additional(1) == 10
    #By the way, m received as an argument is an additional function replaced with a mock.
    #So here too the result is 10.
    #This time I replaced the method, but in the case of a class, it becomes a class.
    print m()
if __name__ == '__main__':
    test_func()
# coding: UTF-8
from mock import patch
def test_func():
    #Specify the method and return value to replace only during this with scope execution
    with patch("Test.Widget.Additional", return_value=10) as m:
        import Test
        w = Test.Widget()
        print w.Additional(1)
        assert w.Additional(1) == 10
        print m()
if __name__ == '__main__':
    test_func()
mock = Mock(spec=SomeClass)
isinstance(mock, SomeClass) #This succeeds
# coding: UTF-8
from mock import Mock, patch
if __name__ == '__main__':
    #A method that returns 3 with the name method,
    #A method that raises a KeyError exception with the name other
    attrs = {'method.return_value': 3, 'other.side_effect': KeyError}
    #You can add attributes at the same time as declaring(some_attribute)。
    mock = Mock(some_attribute='eggs', **attrs)
    print mock.some_attribute
    print mock.method()
    print mock.other()
Another thing that seems to be useful
@patch('sys.stdout', new_callable=StringIO)
So, it will be created as a StringIO object at the time of creation.
You can write a pseudo class for testing and assign it with "Test.Widget =" without using mock. If you don't use the mock's validation feature, that may be faster.
Very useful for testing Django.
pip install webtest
pip install django-webtest
The Django application looks like this:
mysite
|-mysite
|   |-__init__.py
|   |-settings.py
|   |-urls.py
|   |-wsgi.py
|-test app
|   |-__init__.py
|   |-form.py
|   |-modes.py
|   |-views.py
|   |-tests.py Write this test in this file|
|-templates
|-manage.py
Write the contents of tests.py as follows
from django_webtest import WebTest
class TestIndex(WebTest):
    def test_index(self):
        res = self.app.get("/") #Get the response
        #Check the status code and content.
        assert res.status == '200 OK'
        assert 'html' in res
After starting the development server with manage.py runserver, run the test with the following command.
# sudo python manage.py test testapp
Output result
Creating test database for alias 'default'...
.
----------------------------------------------------------------------
Ran 1 test in 0.175s
OK
Destroying test database for alias 'default'...
        Recommended Posts