我最近正在研究的程序中的一个常见任务是以某种方式修改文本文件。(嘿,我在Linux上。所有内容都是一个文件。我进行大规模的系统管理。)
但是代码修改的文件可能不存在于我的桌面盒中。而且,如果它在我的桌面上,我可能不想修改它。
我已经了解了Dive Into Python中的单元测试,并且很清楚我在测试将十进制转换为罗马数字的应用程序时想要做的事情(DintoP中的示例)。测试是完全独立的。您不需要验证程序是否可以正确打印,您只需要验证函数是否将正确的输出返回给定输入即可。
但是,就我而言,我们需要测试程序是否正确修改了其环境。这是我想出的:
1)在标准位置(可能是/ tmp)中创建“原始”文件。
2)运行修改文件的功能,并在/ tmp中将文件的路径传递给它。
3)验证/ tmp中的文件已正确更改;相应地通过/失败单元测试。
对我来说这似乎很困惑。(如果要验证是否正确创建了文件的备份副本,则甚至得到kludgier。)有人可以提出更好的方法吗?
您正在谈论一次太多的测试。如果您通过说“让我们验证它是否正确修改了环境”来尝试攻击测试问题,那么您注定要失败。环境有数十种,甚至数百万种潜在的变化。
相反,请查看程序的各个部分(“单元”)。例如,您将要具有一个确定必须将文件写入何处的函数吗?该功能的输入是什么?也许是环境变量,也许是一些从配置文件读取的值?测试该功能,并且实际上不执行任何修改文件系统的操作。不要传递“现实”值,而是传递易于验证的值。创建一个临时目录,并使用测试setUp方法填充文件。
setUp
然后测试写入文件的代码。只要确保它写入正确的内容文件内容即可。甚至不写入真正的文件系统!您无需为此创建“伪”文件对象,只需使用Python的便捷StringIO模块即可。它们是“文件”接口的“真实”实现,而不仅仅是您的程序实际要写入的实现。
StringIO
最终,您将必须测试最终的所有东西,它们实际上是对真正的顶层函数的传递,该函数传递真实的环境变量和真实的配置文件并将所有内容放在一起。但是不用担心,开始使用它。一方面,当您为较小的功能编写单独的测试时,您将开始挑选技巧,创建测试模拟,假冒和存根将成为您的第二天性。再说一遍:即使您不太想知道如何测试一个函数调用,您也将非常自信地相信它所调用的所有功能都可以正常工作。另外,您会注意到测试驱动的开发迫使您使API更清晰,更灵活。例如:测试称为“open()从抽象的地方来的对象上的方法,而不是测试调用os.open传递的字符串的对象。该open方法是灵活的。它可以被伪造,也可以用不同的方式实现,但是字符串是字符串,os.open不会给您留出任何余地来捕获在其上调用的方法。
open()
os.open
open
您还可以构建测试工具来简化重复性任务。例如,twisted提供了用于创建临时文件的工具,这些文件直接内置于其测试工具中。具有自己的测试库的测试工具或较大项目具有这种功能的情况并不少见。