我们将从最简单的测试生成技术之一开始,随机文本生成(也称为模糊测试)的关键思想是将一串随机字符输入程序,以达到发现故障。
一个简单的模糊器
尝试完成此任务并构建一个模糊生成器。这个想法是生成随机字符,将它们添加到缓冲区字符串变量 () 中,最后返回字符串out。
random.randrange(start, end)-返回一个随机数
range(start, end)-创建一个迭代器
chr(n)-返回一个带有ASCll代码的字符n
import random
def fuzzer(max_length: int = 100, char_start: int = 32, char_range: int = 32)->str:
string_length = random.randrange(0, max_length + 1)
out = ""
for i in range(0, string_length):
out += chr(random.randrange(char_start, char_start + char_range))
return out
该函数返回一串随机字符:fuzzer()
例如,我们还可以生成一系列小写字母。
模糊测试外部程序
如果我们实际调用一个带有模糊测试输入的外部程序会发生什么?首先,我们创建一个包含模糊测试数据的输入文件,然后,我们将此输入文件输入到所选程序中。
创建输入文件
import os
import tempfile
basename = "input.txt"
tempdir = tempfile.mkdtemp()
FILE = os.path.join(tempdir, basename)
print(FILE)
现在可以打开这个文件进行写入
data = fuzzer()
with open(FILE, "w") as f:
f.write(data)
验证该文件是否确实创立并写入
contents = open(FILE).read()
print(contents)
assert(contents == data)
调用外部程序
采用算术表达式对其进行计算
import os
import subprocess
program = "bc"
with open(FILE, "w") as f:
f.write("2 + 2\n")
result = subprocess.run([program, FILE],
stdin=subprocess.DEVNULL,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
universal_newlines=True)
长时间运行的模糊测试
现在让我们将大量输入到我们的测试程序中,看看它是否会在某些程序上崩溃。将所有结果存储在变量中,作为输入数据和实际结果。
trials = 100
program = "bc"
runs = []
for i in range(trials):
data = fuzzer()
with open(FILE, "w") as f:
f.write(data)
result = subprocess.run([program, FILE],
stdin=subprocess.DEVNULL,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
universal_newlines=True)
runs.append((data, result))
模糊测试器的发现
缓冲区溢出
许多程序都内置了输入和输入元素的最大长度。像 C语言中,很容易在程序(或程序员)甚至没有注意到的情况下超过这些长度,从而触发所谓的缓冲区溢出。
模拟缓冲区溢出行为:
def crash_if_too_long(s):
buffer = "Thursday"
if len(s) > len(buffer):
raise ValueError
from ExpectError import ExpectError
trials = 100
with ExpectError():
for i in range(trials):
s = fuzzer()
crash_if_too_long(s)
Traceback (most recent call last):
File "/var/folders/n2/xd9445p97rb3xh7m1dfx8_4h0006ts/T/ipykernel_21451/292568387.py", line 5, in <cell line: 2>
crash_if_too_long(s)
File "/var/folders/n2/xd9445p97rb3xh7m1dfx8_4h0006ts/T/ipykernel_21451/2784561514.py", line 4, in crash_if_too_long
raise ValueError
ValueError (expected)
缺少错误检查
许多编程语言没有异常,而是在特殊情况下有函数返回特殊错误代码。例如,C 函数通常从标准输入返回一个字符;如果不再有可用的输入,则返回特殊值(文件末尾)。