单元测试访问文件的功能

时间:2010-02-17 10:25:55

标签: python unit-testing

我有两个函数 - 一个用于构建一组文件的路径,另一个用于读取文件。以下是两个功能:

def pass_file_name(self):
    self.log_files= []
    file_name = self.path+"\\access_"+self.appliacation+".log"
    if os.path.isfile(file_name):
        self.log_files.append(file_name)
    for i in xrange(7):
         file_name = self.path+"\\access_"+self.appliacation+".log"+"."+str(i+1)
         if os.path.isfile(file_name):
            self.log_files.append(file_name)
    return self.log_files


def read_log_files (self, log_file_names): 
    self.log_entrys = []
    self.log_line = []
    for i in log_file_names:
        self.f = open(i)
        for line in self.f:
            self.log_line = line.split(" ")
            #print self.log_line
            self.log_entrys.append(self.log_line)
    return self.log_entrys

对这两个功能进行单元测试的最佳方法是什么?

4 个答案:

答案 0 :(得分:8)

这里有两个单位

  • 生成文件路径的
  • 第二个读它们

因此应该有两个单元测试用例(即带有测试的类)。首先只测试文件路径生成。第二个是测试从你在tests目录的特殊子目录中准备的预定义文件集读取,它应该与第一个测试用例隔离测试。

在您的情况下,您可能会有非常短的日志文件进行测试。在这种情况下,为了更好的可读性和维护,最好将它们嵌入测试代码中。但在这种情况下,您必须稍微改进您的阅读功能,以便它可以采用文件名类文件对象:

from cStringIO import StringIO

# ...
def test_some_log_reading_scenario(self):
    log1 = '\n'.join([
        'log line',
        'another log line'
    ])
    log2 = '\n'.join([
        'another log another line',
        'lala blah blah'
    ])
    # ...
    result = myobj.read_log_files([StringIO(log1), StringIO(log2)])
    # assert result

答案 1 :(得分:2)

就个人而言,我会在测试这两个函数之前构建一个测试工具来设置所需的文件。

对于每个测试用例(你希望文件存在的位置 - 记得也要测试失败的情况!),将一些已知的日志写入适当命名的文件中;然后调用被测函数并检查结果。

答案 2 :(得分:2)

我不是专家,但我会试一试。首先进行一些重构:使它们起作用(删除所有类的东西),删除不需要的东西。这应该使测试更容易。如果你真的想在类中使用它,你总是可以让类调用这些函数。

def pass_file_name(base_filename, exists):
    """return a list of filenames that exist
       based upon `base_filename`.
       use `os.path.isfile` for `exists`"""

    log_files = []
    if exists(base_filename):
        log_files.append(base_filename)
    for i in range(1, 8):
         filename = base_filename + "." + str(i)
         if exists(filename):
             log_files.append(filename)
    return log_files

def read_log_files (self, log_files):
    """read and parse each line from log_files
       use `pass_file_name` for `log_files`"""

    log_entrys = []
    for filename in log_files:
        with open(filename) as myfile:
            for line in myfile:
                log_entrys.append(line.split())
    return log_entrys

现在,我们可以通过将自定义函数传递给pass_file_name来轻松测试exists

class Test_pass_file_name(unittest.TestCase):
    def test_1(self):
        """assume every file exists
           make sure all logs file are there"""
        exists = lambda _: True
        log_files = pass_file_name("a", exists)
        self.assertEqual(log_files,
                    ["a", "a.1", "a.2", "a.3", 
                     "a.4", "a.5", "a.6", "a.7"])

    def test_2(self):
        """assume no files exists
           make sure nothing returned"""
        exists = lambda _: False
        log_files = pass_file_name("a", exists)
        self.assertEqual(log_files, [])

    # ...more tests here ...

正如我们假设os.path.isfile有效,我们应该对第一个函数进行了很好的测试。虽然您可以始终让测试实际创建一些文件,然后使用pass_file_name调用exists = os.path.isfile

第二个更难测试;有人告诉我,最好的(单元)测试不会触及网络,数据库,GUI或硬盘。所以也许更多的重构会让它变得更容易。嘲笑可以奏效;或者实际上可以在测试函数中编写一些长文件并将其读入。

How do I mock an open used in a with statement (using the Mock framework in Python)?

答案 3 :(得分:1)

将模块中的open名称绑定到一个模拟文件打开的函数。