Unit testing
What is a unit test? Wikipedia defines it this way: unit testing is a method by which individual units of source code, sets of one or more computer program modules together with associated control data, usage procedures, and operating procedures, are tested to determine if they are fit for use.[1] Intuitively, one can view a unit as the smallest testable part of an application. In short, automated tests that verify that the smallest testable unit in a system is functioning correctly. Therefore, the purpose of a unit test is to “verify the responsibilities of the object being tested”. Before writing a unit test, identify the responsibilities of the object being tested so that you know how to write the unit test.
Unit tests can be divided into two broad categories based on who is being tested:
- Unit testing of components that do not depend on external resources: Use the basic unitTest functionality
- Unit testing of components that depend on external resources: Mocks are required
Unittest use
See unit tests for python for a basic use of the python unittest library
Please refer to the following materials for specific usage
- Unit testing in Python
- Ningning. today-Flask Project unit testing practice
- Python UnitTest official documentation
- Geek Academy – Unit tests
- Nicholas – How do YOU write unit tests
mock
Why mock?
I have read many Mocking articles. The best one is Naftuli Kay-an Introduction to Mocking in Python, Mocking in depth by deleting files as An example.
- Python unit tests and Mock tests
- mock-autospec
Rewrite the qk_log logging module as in this article, with the code qk_log.py as follows
#! /usr/bin/env python
# -*- coding: utf-8 -*-
import os
import sys
import datetime
import logging
import logging.handlers
_console_logger = None
_warn_logger = None
_error_logger = None
CONSOLE_FILENAME = 'log/console.log'
WARNING_FILENAME = 'log/warn.log'
ERROR_FILENAME = 'log/error.log'
def log_init() :
if os.path.exists('log/') is True:
pass
else:
os.mkdir('log/')
global _console_logger, _warn_logger, _error_logger
handler = logging.handlers.RotatingFileHandler(
CONSOLE_FILENAME, maxBytes=20*1024*1024, backupCount=5)
hdr = logging.StreamHandler()
_console_logger = logging.getLogger('debug')
_console_logger.addHandler(handler)
_console_logger.addHandler(hdr)
_console_logger.setLevel(logging.DEBUG)
handler = logging.handlers.RotatingFileHandler(
WARNING_FILENAME, maxBytes=20*1024*1024, backupCount=5)
hdr = logging.StreamHandler()
_warn_logger = logging.getLogger('warn')
_warn_logger.addHandler(handler)
_warn_logger.addHandler(hdr)
_warn_logger.setLevel(logging.WARN)
handler = logging.handlers.RotatingFileHandler(
ERROR_FILENAME, maxBytes=20*1024*1024, backupCount=5)
hdr = logging.StreamHandler()
_error_logger = logging.getLogger('error')
_error_logger.addHandler(handler)
_error_logger.addHandler(hdr)
_error_logger.setLevel(logging.ERROR)
def dlog(msg) :
file_name, file_no, unused = find_caler()
time_str = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
_console_logger.debug('[%s] [%s] [%s,%d] %s' % (time_str, 'debug', file_name, file_no, msg))
def ilog(msg) :
file_name, file_no, unused = find_caler()
time_str = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
_console_logger.info('[%s] [%s] [%s,%d] %s' % (time_str, 'info', file_name, file_no, msg))
def wlog(msg) :
file_name, file_no, unused = find_caler()
time_str = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
_console_logger.warn('[%s] [%s] [%s,%d] %s' % (time_str, 'warning', file_name, file_no, msg))
_warn_logger.warn('[%s] [%s] [%s,%d] %s' % (time_str, 'warning', file_name, file_no, msg))
def elog(msg) :
file_name, file_no, unused = find_caler()
time_str = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
_console_logger.error('[%s] [%s] [%s,%d] %s' % (time_str, 'error', file_name, file_no, msg))
_error_logger.error('[%s] [%s] [%s,%d] %s' % (time_str, 'error', file_name, file_no, msg))
def find_caler() :
f = sys._getframe(2)
co = f.f_code
return (os.path.basename(co.co_filename), f.f_lineno, co.co_name) ifco ! =None else ('unknown'.0.'unknown')
if __name__ == '__main__':
log_init()
dlog('test.log %d'% (123))
ilog('test.log %d' % (123))
wlog('test.log %d' % (123))
elog('test.log %d' % (123))
Copy the code
The unit test code is as follows:
#! /usr/bin/env python
# -*- coding: utf-8 -*-
""" Created on 10/10/17 11:27 AM @author: Chen Liang @function: Unit Test for log module ""
import sys
reload(sys)
sys.setdefaultencoding('utf-8')
import unittest
import mock
import datetime
from qk_log import log_init, dlog, ilog, wlog, elog
class TestQkLog(unittest.TestCase) :
dt_str = datetime.datetime.strptime('the 2017-10-11 11:08:59'.'%Y-%m-%d %H:%M:%S')
@mock.patch('qk_log.os.path')
@mock.patch('qk_log.datetime.datetime')
@mock.patch('qk_log.logging')
@mock.patch('qk_log.find_caler')
def test_dlog(self, mock_caler, mock_logging, mock_datetime, mock_path) :
mock_path.exists.return_value = True
log_init()
self.assertFalse(mock_logging.getLogger('debug').debug.called, "Failed to not write log.")
mock_caler.return_value = ('qk_log_test'.12.' ')
mock_datetime.now.return_value = self.dt_str
dlog('any msg')
mock_logging.getLogger('debug').debug.assert_called_with(
'[%s] [%s] [%s,%d] %s' % ('the 2017-10-11 11:08:59'.'debug'.'qk_log_test'.12.'any msg'))
@mock.patch('qk_log.os.path')
@mock.patch('qk_log.datetime.datetime')
@mock.patch('qk_log.logging')
@mock.patch('qk_log.find_caler')
def test_ilog(self, mock_caler, mock_logging, mock_datetime, mock_path) :
mock_path.exists.return_value = True
log_init()
self.assertFalse(mock_logging.getLogger('debug').info.called, "Failed to not write log.")
mock_caler.return_value = ('qk_log_test'.12.' ')
mock_datetime.now.return_value = self.dt_str
ilog('any msg')
mock_logging.getLogger('debug').info.assert_called_with(
'[%s] [%s] [%s,%d] %s' % ('the 2017-10-11 11:08:59'.'info'.'qk_log_test'.12.'any msg'))
@mock.patch('qk_log.os.path')
@mock.patch('qk_log.datetime.datetime')
@mock.patch('qk_log.logging')
@mock.patch('qk_log.find_caler')
def test_wlog(self, mock_caler, mock_logging, mock_datetime, mock_path) :
mock_path.exists.return_value = True
log_init()
self.assertFalse(mock_logging.getLogger('warn').info.called, "Failed to not write log.")
mock_caler.return_value = ('qk_log_test'.12.' ')
mock_datetime.now.return_value = self.dt_str
wlog('any msg')
mock_logging.getLogger('warn').warn.assert_called_with(
'[%s] [%s] [%s,%d] %s' % ('the 2017-10-11 11:08:59'.'warning'.'qk_log_test'.12.'any msg'))
@mock.patch('qk_log.os.path')
@mock.patch('qk_log.datetime.datetime')
@mock.patch('qk_log.logging')
@mock.patch('qk_log.find_caler')
def test_elog(self, mock_caler, mock_logging, mock_datetime, mock_path) :
mock_path.exists.return_value = True
log_init()
self.assertFalse(mock_logging.getLogger('error').info.called, "Failed to not write log.")
mock_caler.return_value = ('qk_log_test'.12.' ')
mock_datetime.now.return_value = self.dt_str
elog('any msg')
mock_logging.getLogger('error').error.assert_called_with(
'[%s] [%s] [%s,%d] %s' % ('the 2017-10-11 11:08:59'.'error'.'qk_log_test'.12.'any msg'))
if __name__ == '__main__':
unittest.main()
Copy the code
Views on unit testing
Unit testing was introduced during an overall transformation of the Python statistical analysis project. After writing the unit tests for the common library, the team found that the time spent on unit tests was too much, the common library did not change often, and the business logic was confused, so the team decided to abandon unit testing. There is no need to write unit tests for the projects of startups and start-up teams that go live quickly, because when all changes are possible, the corresponding unit tests will be discarded when the code is discarded, which wastes too much manpower.
Therefore, the start-up team does not recommend writing unit tests, just do a good job of burying the program and monitoring the alarm.
Please give me a thumbs up!
Carefully organized the computer from all directions from the entry, advanced, actual combat video courses and e-books, according to the catalog reasonable classification, always can find you need to learn information, what are still waiting for? Go to download!!
Can’t forget, there will be echoes, friends to help me like it, thank you very much.
I am a senior software engineer of YY with four years of work experience. I refuse to be a slashes programmer.
Listen to me. It’s a lot of progress
If lucky enough to be able to help you, please help me [like], give a attention, if you can along with comments to encourage, will be very grateful.
List of articles: More
All my articles, answers and copyright protection platform cooperation, copyright belongs to the workplace Liangge all, unauthorized, reproduced will investigate!