7

我编写了一个脚本,它可以打开一个文件、读取内容并进行一些操作和计算,并将它们存储在集合和字典中。

我将如何为这样的事情编写单元测试?我的问题具体是:

  1. 我会测试文件是否打开?
  2. 该文件很大(它是 unix 字典文件)。我将如何对计算进行单元测试?我真的必须手动计算所有内容并测试结果是否正确吗?我有一种感觉,这违背了单元测试的全部目的。我没有通过标准输入接受任何输入。
4

3 回答 3

16

这不是单元测试的意义所在!

  1. 您的文件不代表一个单位,所以不,您不测试文件或使用文件!
  2. 您的单元测试应该测试处理 a) 文件处理 b) 计算的函数/方法的每一个方法
  3. 您的单元测试超出被测单元的代码行的情况并不罕见。

单元测试意味着(不完整,也不是书本定义):

  • 简约/原子 - 您将单位拆分为可能的最基本/最简单的单位;单元通常是可调用的(方法、函数、可调用对象)
  • 关注点分离——你在每一个测试中只测试一件事;如果要测试单个单元的不同条件,则编写不同的测试
  • 确定性 - 你给单位一些东西来处理,事先知道它的结果应该是什么
  • 如果您的被测单元需要特定的环境,您可以创建一个fixture/test-setup/mock-up
  • 单元测试(根据经验)非常快!如果速度很慢,请检查您是否从上方违反了另一点
  • 如果您需要测试某些违反上述某些内容的内容,您可能已经在集成测试的测试中迈出了下一步
  • 您可以使用单元测试框架而不是单元测试,但不要仅仅因为使用单元测试框架而将其称为单元测试

这个人(Gary Bernhardt)有一些有趣的实际例子来说明测试和单元测试的含义。

更新一些澄清:

“1. 我会测试文件是否打开了吗?”

好吧,您可以这样做,但是“单位”是什么?请记住,测试只有两种解决方案:通过和失败。如果您的测试失败,它应该(理想情况下必须)只有一个原因:您的单元(=函数)很烂!但是在这种情况下,您的测试可能会失败,因为: * 文件不存在 * 已锁定 * 已损坏 * 没有文件句柄 * 内存不足(大文件) * 月相等等。

那么失败(或通过)“单元”测试对您的单元有何影响?您不会单独测试您的单元,而是测试整个周围的环境。这更像是一个系统测试!如果您想测试是否成功打开文件,您至少应该模拟一个文件。

“2 ...我将如何对计算进行单元测试?我真的必须手动计算所有内容并测试结果是否正确吗?”

不。您将为极端情况和常规情况编写测试,并根据已处理的情况检查预期结果。所需测试的数量取决于计算的复杂性和规则的例外情况。

例如:

def test_negative_factor(self):
   assert result 

def test_discontinuity(self):
   assert raise exception if x == undefined_value

我希望我让自己更清楚!

于 2012-11-22T21:48:07.240 回答
6

您应该将代码重构为可单元测试。那,在我的头顶上,会说:

  1. 将文件打开的功能放到一个单独的单元中。使该新单元接收文件名,并返回内容流。
  2. 让您的单元接收流并读取它,而不是打开文件并读取它。
  3. 为您的主要(计算)单元编写单元测试。您需要模拟一个流,例如来自字典。编写几个测试用例,每次为您的单元提供不同的流,并确保您的单元为每个输入计算正确的数据。
  4. 尽可能让您的代码覆盖率接近 100%。使用鼻子测试进行覆盖。
  5. 最后,为您的“流提供者”编写一个测试。向它提供几个文件(将它们存储在您的测试文件夹中),并确保您的流提供者正确读取它们。
  6. 让第二个单元测试的覆盖率尽可能接近 100%。
  7. 现在,也只有现在,提交您的代码。
于 2013-02-06T16:07:30.213 回答
0

您还没有解释计算是什么,但我想您的程序也应该能够处理大文件的一个子集。如果是这种情况,请进行单元测试,打开一个小文件,进行计算并产生一些结果,您可以验证它是正确的。

于 2012-11-22T21:39:12.937 回答