Модульное тестирования на Python на примере копирования файлов

На днях встала задача написать скрипт копирующий новые файлы из одной директории в другую и пропускать уже скопированные. Если возникают какие-либо ошибки, то все они записываются в лог. Хочу обратить ваше внимание, что все тестовые методы изолированны друг от друга, так что если сломается один метод, то другие продолжат выполняться. А так же методы setUp и tearDown подготавливают среду для выполнения тестов.
Модуль с тестами скопируйте, например, в файл LogCopiedFilesTest.py. Зайдя в папку с модулем запустите python LogCopiedFilesTest.py


'''

Created on 08.12.2010


@author: Razzhivn A.S.

@site: httpbots.com
'''

import unittest
from file_utils import CopyFilesUtil
import os
from shutil import rmtree

class LogCopiedFilesTest(unittest.TestCase):

    dst_dir = os.path.abspath('dst_dir')
    src_dir = os.path.abspath('src_dir')
    log = os.path.abspath('log.txt')
    cpFileName = 'file_1'

 
    def setUp(self):
        os.mkdir(self.dst_dir)
        os.mkdir(self.src_dir)
        self.logcpfiles = CopyFilesUtil(self.src_dir, self.dst_dir, self.log)
        self.createTestSrcFiles()
        
    def tearDown(self):
        os.remove(self.log)
        rmtree(self.dst_dir)
        rmtree(self.src_dir)   

    def testCopyUnlogedFiles(self):
        self.logcpfiles.write_copylog(self.cpFileName)
        self.logcpfiles.copyUnlogedFiles()
        assert not self.cpFileName in os.listdir(self.dst_dir)
        
    def testCopy(self):
        self.logcpfiles.copy(self.cpFileName)
        assert os.path.exists(os.path.join(self.dst_dir, self.cpFileName))
    
    def testReadWriteCopyLog(self):
        self.logcpfiles.write_copylog(self.cpFileName)
        filenames = self.logcpfiles.read_copylog()
        assert self.cpFileName in filenames

    def testDstDirUnexists(self):
        unexist_dir = 'Z:\\'
        self.logcpfiles = CopyFilesUtil(self.src_dir, unexist_dir, self.log)
        self.logcpfiles.copyUnlogedFiles()
        assert not self.logcpfiles.read_copylog()
        assert os.path.exists(self.logcpfiles.error_log)
        os.remove(self.logcpfiles.error_log)

    def createTestSrcFiles(self):
        for i in range(0,4):
            open(os.path.join(self.src_dir, '%s%s'%(self.cpFileName[:-1], i)), 'w').close()


if __name__ == "__main__":
    #import sys;sys.argv = ['', 'Test.testName']
    unittest.main()

А вот и сам файл file_utils.py:


#!/usr/bin/python
# -*- coding: utf-8 -*-

'''
Created on 08.12.2010
@author: Razzhivin A. S.
@site: httpbots.com
'''

import os
from shutil import copyfile
from time import localtime, strftime

def writeErrorLog(error_log, msg):    
    '''Записать лог ошибок
    >>> writeErrorLog('error.log', 'error message')
    >>> f = open('error.log', 'r')
    >>> 'error message' in f.readline()
    True
    >>> f.close()
    >>> os.remove('error.log')
    '''
    if not os.path.exists(error_log):
        open(error_log, 'w').close()    
    t = strftime("%d/%m/%Y %H:%M:%S", localtime())
    f = open(error_log, 'a')
    f.write('[%s] %s' % (t, msg))
    f.close()

class CopyFilesUtil:

    error_log = os.path.abspath('cp_error.log')

    def __init__(self, src_dir, dst_dir, copylog):
        '''@param src_dir: откуда
           @param dst_dir: куда
           @param copylog: лог файлов которые уже были скопированы'''
        self.src_dir = src_dir
        self.dst_dir = dst_dir
        self.copylog = copylog

        # если лог файла нет, то надо его создать
        if not os.path.exists(self.copylog):
            open(self.copylog, 'w').close()

    def copyUnlogedFiles(self):
        '''Скопировать файлы, которых нет в логе'''
        try:
            copied_files = self.read_copylog()
            for f in os.listdir(self.src_dir):
                if not (f in copied_files):
                    self.copy(f)
                    self.write_copylog(f)
        except OSError as e:
            writeErrorLog(self.error_log, "File doesn't exists. "+e.__str__()+"\n")
        except Exception as e:
            writeErrorLog(self.error_log, e.__str__())

    def read_copylog(self):
        f = open(self.copylog, 'r')
        filenames = [line.rstrip('\n') for line in f.readlines()]
        f.close()
        return filenames

    def write_copylog(self, filename):
        f = open(self.copylog, 'a')
        f.write(filename+'\n')
        f.close()

    def copy(self, file):
        '''Копирует файл из src_dir в dst_dir. dst_dir создаётся в случае отсутсвия 
           @param file: копируемый файл'''
        src_fpath = os.path.join(self.src_dir, file)
        dst_fpath = os.path.join(self.dst_dir, file)
        if not os.path.exists(self.dst_dir):
            os.makedirs(self.dst_dir)

        copyfile(src_fpath, dst_fpath)

def main():
    try:
        lgcpf = CopyFilesUtil('E:\\tmp\\CTC', 'Z:\\', 'E:\\tmp\\copy_log.txt')
        lgcpf.copyUnlogedFiles()
    except Exception as e:
        writeErrorLog(CopyFilesUtil.error_log, e.__str__())

if __name__ == '__main__':
    import doctest
    doctest.testmod()
    main()

Ещё пару слов про магические методы setUp и tearDown. Эти методы запускаются перед выполнением каждого тестового метода. Поэтому эти методы служат для подготовки среды выполнения методов. И ещё, последовательность вызова тестовых методов случайная. Для простых функций утилит вполне подходит doctest, поэтому я протестил метод writeErrorLog с его помощью.
Думаю, что получившиеся тесты довольно информативны. Разобраться в том, как работает не составит труда. p.s. под linux-ом один тест не пройдёт=) В качестве упражнения можете разобраться почему))

Логин Регистрация

Логин

Облако тэгов

count count all django django admin feedparser libxml2dom linux mysql parser payway python pyunit pyvkapi qiwi return sniffer sockets ssh ssh tunnel sublime text tdd tehtv templatetags ubuntu unittest webmoney X11 аргументы биллинг видео видеоурок видео уроки вконтакте возврат диаграмма диаграмма стека заметки инструкция комментарии композиция логические операторы мышка образование обучение операторы параметры функции парсинг переменная переменные питон платежи поток выполнения преобразование типов программирование проекты процессинг разработка разработкаразработка рекурсия сеть скрипт сниффер сокеты стек стоки тестирование тип тип данных типы урок уроки условия функция
free counters