【问题标题】:Unit testing functions that access files访问文件的单元测试函数
【发布时间】:2011-01-17 19:12:46
【问题描述】:

我有两个函数——一个构建一组文件的路径,另一个读取文件。下面是两个函数:

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

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

【问题讨论】:

    标签: python unit-testing


    【解决方案1】:

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

    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
    

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

    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 有效时,我们应该对第一个函数进行了很好的测试。尽管您总是可以让测试实际创建一些文件,然后使用exists = os.path.isfile 调用pass_file_name

    第二个更难测试;有人告诉我,最好的(单元)测试不涉及网络、数据库、GUI 或硬盘驱动器。所以也许更多的重构会使它更容易。模拟开放可以工作;或者实际上可以在测试函数中写入一些长文件并将它们读入。

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

    【讨论】:

      【解决方案2】:

      这里有两个单位

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

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

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

      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
      

      【讨论】:

      • "... 所以它可以采用文件名或类似文件的对象" 我该怎么做?检查 str (文件名)的实例,否则假设它是一个 IO 对象?
      【解决方案3】:

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

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

      【讨论】:

        【解决方案4】:

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

        【讨论】:

        • 抱歉,这里是全新的。我该怎么做呢?就像模拟文件打开一样?
        • 编写一个类文件对象,实现代码所需的各种file 方法,然后从fake_open() 函数返回一个实例。导入模块然后执行somemodule.open = fake_open.
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2013-07-04
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-09-02
        • 1970-01-01
        • 2015-07-13
        相关资源
        最近更新 更多