单元测试文件修改

单元测试文件修改

问题描述:

我最近正在研究的程序中的一项常见任务是以某种方式修改文本文件. (嘿,我在Linux上.所有内容都是文件.我进行大规模的系统管理.)

A common task in programs I've been working on lately is modifying a text file in some way. (Hey, I'm on Linux. Everything's a file. And I do large-scale system admin.)

但是代码修改过的文件可能不存在于我的桌面盒中.而且,如果它在我的桌面上,我可能不想修改它.

But the file the code modifies may not exist on my desktop box. And I probably don't want to modify it if it IS on my desktop.

我已经了解了Dive Into Python中的单元测试,并且很清楚我在测试将十进制转换为罗马数字的应用程序时想要做的事情(DintoP中的示例).测试是完全独立的.您无需验证程序是否可以正确打印,只需验证函数是否将正确的输出返回给定输入即可.

I've read about unit testing in Dive Into Python, and it's pretty clear what I want to do when testing an app that converts decimal to Roman Numerals (the example in DintoP). The testing is nicely self-contained. You don't need to verify that the program PRINTS the right thing, you just need to verify that the functions are returning the right output to a given input.

但是,就我而言,我们需要测试程序是否正确修改了其环境.这是我想出的:

In my case, however, we need to test that the program is modifying its environment correctly. Here's what I've come up with:

1)在标准位置(也许是/tmp)中创建原始"文件.

1) Create the "original" file in a standard location, perhaps /tmp.

2)运行修改文件的功能,将其路径传递到/tmp中的文件.

2) Run the function that modifies the file, passing it the path to the file in /tmp.

3)验证/tmp中的文件是否已正确更改;通过/失败单元测试.

3) Verify that the file in /tmp was changed correctly; pass/fail unit test accordingly.

对我来说这似乎很困惑. (如果要验证是否正确创建了文件的备份副本,甚至会得到kludgier,等等.)有人可以提出更好的方法吗?

This seems kludgy to me. (Gets even kludgier if you want to verify that backup copies of the file are created properly, etc.) Has anyone come up with a better way?

您正在谈论一次太多的测试.如果您通过说让我们确认它正确地修改了环境"来尝试攻击测试问题,那么您注定要失败.环境具有数十种甚至数百万种潜在的变化.

You're talking about testing too much at once. If you start trying to attack a testing problem by saying "Let's verify that it modifies its environment correctly", you're doomed to failure. Environments have dozens, maybe even millions of potential variations.

相反,请查看程序的各个部分(单元").例如,您将要具有一个确定必须将文件写入何处的函数吗?该功能的输入是什么?也许是环境变量,也许是从配置文件中读取的一些值?测试该功能,并且实际上不执行任何修改文件系统的操作.不要传递真实"值,而是传递易于验证的值.创建一个临时目录,并使用测试的setUp方法中的文件填充该目录.

Instead, look at the pieces ("units") of your program. For example, are you going to have a function that determines where the files are that have to be written? What are the inputs to that function? Perhaps an environment variable, perhaps some values read from a config file? Test that function, and don't actually do anything that modifies the filesystem. Don't pass it "realistic" values, pass it values that are easy to verify against. Make a temporary directory, populate it with files in your test's setUp method.

然后测试写入文件的代码.只要确保它正在写入正确的内容文件内容即可.甚至不要写入真实的文件系统!您无需为此创建伪"文件对象,只需使用Python方便的StringIO模块即可.它们是文件"接口的真实"实现,而不仅仅是您的程序实际上要写入的接口.

Then test the code that writes the files. Just make sure it's writing the right contents file contents. Don't even write to a real filesystem! You don't need to make "fake" file objects for this, just use Python's handy StringIO modules; they're "real" implementations of the "file" interface, they're just not the ones that your program is actually going to be writing to.

最终,您将必须测试最终的所有东西,实际上是针对真正的*函数,它传递了真实的环境变量和真实的配置文件,并将所有内容放在一起.但是,不必担心该开始.一方面,在编写针对较小功能的单独测试时,您将开始学到技巧,创建测试模拟,伪造品和存根将成为您的第二天性.再说一遍:即使您不太想知道如何测试一个函数调用,您也会非常自信地知道它所调用的所有功能都可以正常工作.此外,您会注意到测试驱动的开发迫使您使API更清晰,更灵活.例如:在抽象对象上测试调用open()方法的对象要比在传递它的字符串上测试调用os.open的对象容易得多. open方法很灵活;它可以伪造,也可以用不同的方式实现,但是字符串是字符串,os.open没有任何余地来捕获调用它的方法.

Ultimately you will have to test the final, everything-is-actually-hooked-up-for-real top-level function that passes the real environment variable and the real config file and puts everything together. But don't worry about that to get started. For one thing, you will start picking up tricks as you write individual tests for smaller functions and creating test mocks, fakes, and stubs will become second nature to you. For another: even if you can't quite figure out how to test that one function call, you will have a very high level of confidence that everything which it is calling works perfectly. Also, you'll notice that test-driven development forces you to make your APIs clearer and more flexible. For example: it's much easier to test something that calls an open() method on an object that came from somewhere abstract, than to test something that calls os.open on a string that you pass it. The open method is flexible; it can be faked, it can be implemented differently, but a string is a string and os.open doesn't give you any leeway to catch what methods are called on it.

您还可以构建测试工具来简化重复性任务.例如,twisted提供了用于创建用于测试直接安装在其测试工具中.具有自己的测试库的测试工具或大型项目具有这种功能的情况并不少见.

You can also build testing tools to make repetitive tasks easy. For example, twisted provides facilities for creating temporary files for testing built right into its testing tool. It's not uncommon for testing tools or larger projects with their own test libraries to have functionality like this.