我有两个函数 - 一个用于构建一组文件的路径,另一个用于读取文件。以下是两个功能:
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
对这两个功能进行单元测试的最佳方法是什么?
答案 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
名称绑定到一个模拟文件打开的函数。