【问题标题】:Writing tests for file parser functions in a modular way以模块化方式为文件解析器函数编写测试
【发布时间】:2016-01-06 02:21:15
【问题描述】:

我正在编写一段 python 代码,它将格式化文件解析为 python 对象。该文件可能会有所不同,但目前我正在根据文件可能的一个子集进行工作,并希望测试可以帮助我为所有这些文件扩展它。

文件本身由一个包含元数据的标头组成,后跟几个数据块。

[general header, describes length of header 1 & header 2]
[header describing data block 1]
[header describing data block 2]
[data block 1]
[data block 2]

目前我的代码大致如下

with datafile as open(filename, 'r'):
    gen_header_obj = parse_gen_header(datafile)
    header1_obj = parse_header1(datafile, gen_header_obj.header1_len)
    header2_obj = parse_header2(datafile, gen_header_obj.header2_len)
    data1_obj = parse_data1(datafile, header1_obj.datalen)
    data2_obj = parse_data2(datafile, header2_obj.datalen)

其中每个 parse*(file) 函数调用 file.readline() 多次,具体取决于指定数据长度的大小。

理想情况下,我将至少进行 5 次单独的测试,在其中我提供文件的虚假部分并查看它是否正确获取信息。除了在这种情况下,数据部分非常大(兆字节)。

是否可以编写类似于以下内容的测试?

class TestParser(unittest.TestCase)
    filename = 'locally_stored_file.txt'

    def setUp(self):
        self.file = open(filename, 'r')

    def tearDown(self):
        self.file.close()

    def test_gen_header_parse(self):
        result = parse_gen_header(datafile)
        self.header1_len = result.header1_len
        self.header2_len = result.header2_len
        expected = ...
        assertIsEqual(result, expected)

    def test_header1_parse(self):
        # datafile.seek() is left of from test_gen_header_parse
        result = parse_header1(datafile, self.header1_len)
        self.data1_len = result.data1_len
        expected = ...
        assertIsEqual(result, expected)

    def test_header2_parse(self):
        # datafile.seek() is left of from test_header1_parse
        result = parse_header2(datafile, self.header2_len)
        self.data2_len = result.data2_len
        expected = ...
        assertIsEqual(result, expected)

    def test_data1_parse(self):
        # datafile.seek() is left of from test_header2_parse
        result = parse_data1(datafile, self.data1_len)
        expected = ...
        assertIsEqual(result, expected)

    def test_data2_parse(self):
        # datafile.seek() is left of from test_data1_parse
        result = parse_data2(datafile, self.data2_len)
        expected = ...
        assertIsEqual(result, expected)

    # Some code to force the tests to run sequentially as laid out above

如您所见,我正在尝试编写五个单独的测试,如果将来出现问题,它们有望单独失败。但是,如果不事先运行 parse_gen_headerparse_header1,我将无法测试 parse_header2

不确定是否有更好的方法来解决这个问题。

【问题讨论】:

  • 您可以更改数据文件格式以方便测试,还是由其他人/其他人确定,您必须调整代码来适应它?因为我真的建议在文件正文中引入一些标准标志来表示标题/数据块的开始和结束,但是在你的情况下这可能是不可能的。
  • 它是一个可执行程序的输出,更具体地说,它是一个格式化的中子截面数据文件,其中数据格式取决于几个物理事物(同位素、迁移态、可用测量值)。

标签: python file unit-testing testing automated-tests


【解决方案1】:

如果您事先声明所有长度并使用seek 函数为每个测试适当地移动文件指针会更好。您还可以使用预期的长度并对其进行测试

class TestParser(unittest.TestCase)
    filename = 'locally_stored_file.txt'
    expected_gen_header_length = 42 # The correct number it should be
    expected_header1_length = 42 # The correct number it should be
    # and lengths of the other things

    def test_gen_header_parse(self):
        with datafile = open(filename, 'r'):
            result, len_header = parse_gen_header(datafile) # output len_header if you want to do an assert for it
            self.header1_len = result.header1_len
            self.header2_len = result.header2_len
            expected = ...
            assertIsEqual(self.expected_gen_header_length, len_gen_header)
            assertIsEqual(result, expected)

    def test_header1_parse(self):
        with datafile = open(filename, 'r'):
            # Force datafile.seek() to begin after gen_header
            datafile.seek(self.expected_gen_header_length)

            result = parse_header1(datafile, self.expected_header1_length)
            self.data1_len = result.data1_len
            expected = ...
            assertIsEqual(result, expected)

    # and so on ....

【讨论】:

  • 您确定文本文件中的字节偏移是个好主意吗?行偏移会更有意义,但由于它是一个文本文件(因此可能是手动编辑的),我什至都不相信它们。
  • 谢谢,+1 因为这是我可以采用的一种方法,可以从每个测试文件中推断出预期的标头长度等。在考虑了一夜之后,我决定使用模拟文件,稍后将发布该答案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-03-29
  • 2012-06-30
  • 2021-06-10
  • 2011-05-30
相关资源
最近更新 更多