有什么资格作为单元测试&什么是合格的功能/集成测试?

时间:2014-03-03 16:09:49

标签: c# unit-testing

我对单元测试和集成/功能测试的限制有点困惑?这些之间是否有明确的界限?

让我先从一个场景开始......

如果我有一组执行过程的类。每个流程都包含一些任务。

ProcessA {
   var a = do TaskA;
   var c = do TaskC;
   var b = do TaskB;
}

ProcessB {
   var c = do TaskC;
   var d = do TaskD;
}

ProcessC {
   var a = do TaskA;
   var d = do TaskD;
}

如果我们采用上述设计,那么我可以编写单元测试来测试每个任务,以确保它们按照预期执行。我很酷。

我的问题出现在我想为所有进程编写单元测试,或者我认为它们将是单元测试。我想确保任务的顺序正确,业务规则在流程本身内是正确的。

单元测试的定义是单元测试测试代码的一口大小。我试图测试的是一个更大的'ProcessA','ProcessB'代码。在那些测试中,我仍将与数据存储区和数据存储区分离。服务。这仍然被认为是单元测试或集成/功能测试吗?

更新

根据所有评论,我想要提出的正确问题是,如果所有外部依赖项都在“ProcessA”,“ProcessB”等类中进行了模拟,那么这些类的单元测试是否会被视为单元测试还是整合测试?

感谢您对我的耐心......

3 个答案:

答案 0 :(得分:2)

一旦你说I want to make sure that the tasks are in the proper order, and the business rules are correct within the process itself.你就停止谈论单元测试并开始讨论集成测试。

即使您正在测试商务规则的数据存储和服务。如果您的组织与我的组织类似,那么业务规则可以(并且通常会)发生变化。正是这种易变性使其成为集成测试。

我使用的基本规则是“单元测试是模块化的,独立的代码片段,不依赖于外部数据源。而集成测试是需要的测试使用外部数据源,无论是模拟还是来自生产。“

单元测试的艺术,第二版列出了具有以下定义的集成测试:

  

我将集成测试视为任何不快速且一致的测试,并且使用测试单元的一个或多个实际依赖性。例如,如果测试使用实际系统时间,真实文件系统或真实数据库,它已进入集成测试领域。

以及以下(强调我的)单元测试:

  

单元测试是一段自动代码,用于调用正在测试的工作单元,然后检查有关该单元的单个最终结果的一些假设。单元测试几乎总是使用单元测试框架。它可以轻松编写并快速运行。它值得信赖,易读且易于维护。只要生产代码没有改变,它的结果就是一致的。

基于与上述相同的书。单元测试:

  • Is an automated piece of code that invokes a different method and then checks some assumptions on the logical behaviour of that method or class.
    • 如果您可以将ProcessA/B/C缩减为可以彼此独立测试的小块,则会出现这种情况。
  • can be executed repeatedly by anyone on the development team.
    • 如果您团队中的某人需要参考值或备忘单来确定测试是否通过,则不是单元测试。

现在根据您的编辑情况而定。集成测试和单元测试可以重叠,许多其他开发人员可能对如何标记测试有不同的想法。

您的问题的答案是确定您和您的开发团队的最佳实践。如果达成共识,那就是单元测试,那就考虑一下。

单元和集成测试应帮助进程,而不是阻碍它。请不要让语义妨碍它。

答案 1 :(得分:1)

预留工具等... 单元测试只是测试一段特定代码,通常由程序员执行。

功能和集成通常由QA团队执行:

功能测试正在测试代码是否符合预期目的。

集成测试是关于测试代码并测量它与系统的其他模块/部分交互的方式。

答案 2 :(得分:1)

我会说单元测试是仅测试一个类(一个单元)的测试,而集成测试测试多个类/程序集和/或甚至外部数据源的集成。功能测试应该明确地测试暴露给用户的功能(可能是开发团队之外的内部用户等)。

编辑: 实现复合类的单元测试的唯一方法是使用dependency injection。这意味着您应该定义一个接口(可能不止一个),例如:

interface ITask
{
  Perform();
}

并将其注入Process班级:

class ProcessC
{
  ITask taskA;
  ITask taskD;
  ProcessA(ITask taskA, ITask taskD)
  {
    this.taskA = taskA;
    this.taskD = taskD;
  }

  void Run() //change to your real methods
  {
    taskA.Perform(); //capture results
    taskD.Perform();
  }
}

现在您可以模拟注入的接口ITask(使用mocking framework),以便您可以将进程的行为与任务的行为隔离开来。