5

我已经编写了我的单元测试,并且在需要外部资源的地方使用假货来处理。

到目前为止一切都很好。现在我面临着其他测试阶段,主要是集成,我想针对真实的外部资源(例如数据库)重复单元测试方法。

那么,对于构建单元与集成测试的测试项目有哪些建议?我知道有些人更喜欢单元和集成的单独程序集?

如何在两个程序集之间共享通用测试代码?我应该创建一个包含所有抽象测试类的第三程序集并让单元和集成继承吗?我正在寻找最大的可重用性...

我听到很多关于依赖注入(StructureMap)的噪音,如何在给定的单元+集成测试设置中使用这样的工具?

谁能分享一些智慧?谢谢

4

7 回答 7

1

对于将在设置和拆卸阶段执行的代码,基类方法可以很好地工作。对于集成测试,您可以将单元测试的功能提取到参数化良好的非测试方法中(最好放在另一个命名空间中),并从单元测试和集成测试中调用这些“通用”方法。将单元测试、集成测试和常用方法放入单独的命名空间就足够了,不需要额外的程序集。

于 2009-08-28T15:19:48.640 回答
1

我认为您不应该在物理上将两者分开。一个好的解决方案是将 Microsoft.TeamFoundation.PowerTools.Tasks.CategoryAttribute 放在您的测试之上,以识别常规测试和集成测试。运行测试时(即使使用 MSBuild),您可以决定只运行您感兴趣的测试。

或者,您可以将它们放在单独的名称空间中。

于 2009-06-10T14:44:21.113 回答
0

一种方法是使用可在多个测试上下文中使用的辅助方法创建一个单独的文件,然后将该文件包含在您的单元测试和功能测试中。对于变化的部分,您可以使用依赖注入 - 例如,通过传入不同的工厂。在单元测试中,工厂可以构建一个假对象,而在功能测试中,它可以将一个真实对象插入到您的测试数据库中。

于 2009-06-10T15:04:46.890 回答
0

是将测试拆分为两个项目还是将它们保留在一个项目中可能取决于您拥有的类/测试的数量。单个项目中的类太多会使挖掘变得困难。如果您确实将它们分开,则可以将辅助/通用方法放入第三个程序集中,或者您可以在单元测试程序集中将它们公开,并让集成程序集引用该程序集。让事情变得尽可能复杂。

于 2009-06-10T15:11:08.000 回答
0

经过一些试验,这是您可以重用测试方法的方法:

    public abstract class TestBase
    {
        [TestMethod]
        public void BaseTestMethod()
        {
            Assert.IsTrue(true);
        }
    }


    [TestClass]
    public class UnitTest : TestBase
    {
    }

    [TestClass]
    public class IntegrationTest : TestBase
    {
    }

单元和集成测试类将选取基类测试方法并将它们作为两个单独的测试运行。

您应该能够在基类上创建一个参数化的构造函数来注入您的模拟或资源。

我认为这种方法可以在同一个程序集中与类一起使用。所以看起来现在必须使用单一的组装方法。

感谢ppl的提示!

于 2009-06-11T04:46:25.200 回答
0

在我们的项目中,我们将集成和单元测试放在一起,但在不同的文件夹中。我们的项目布局是这样的,我们为主要部分(域、服务等)提供了单独的程序集。每个组件都有一个匹配的测试组件。允许测试程序集引用其他测试程序集。

这意味着 Services.Test 可以引用 Domain.Test ,这对我们来说很有意义,因为 Services 在实际代码中引用了 Domain。

就可重复使用的部分而言,我们有

  • Builders - 这些提供了一个流畅的界面来创建我们领域中最重要/最复杂的对象。这些位于我们域的主测试文件夹中。我们的域测试程序集被所有其他测试程序集引用。

  • Mothers - 这些将数据插入数据库。他们为插入的行返回一个 ID,如果需要,可以使用它来加载对象。这些位于我们服务的主测试文件夹中。

  • 助手——这些人在我们的测试过程中会做一些小事。例如,我们更喜欢允许通过 IEnuermable 访问集合,因此我们有一个 CollectionHelper.AssertCountIsEqualTo<_T>(int count, IEnumerable<_T> collection, string message),它将 IEnumerable 包装在一个 List 中并声明一个计数。我们的助手都生活在一个共同的测试中,其他所有测试都会引用该测试。

至于 IoC 容器,如果您可以在您的项目中使用它,那么它们不仅可以在测试(通过自动模拟)方面提供巨大帮助,而且可以在一般开发中提供巨大帮助。无意中听到使用包含注册所有内容,尽管这对于测试来说可能有点多。

于 2009-06-10T19:33:11.980 回答
0

如果您的许多单元测试和相应的集成测试之间的唯一区别是后者使用“真实”资源而不是假货(模拟),则一种方法如下:

  1. 从外部为您的测试类提供一个标志 is_unit_test
  2. 在类设置中,根据标志提供虚假或真实资源。例如,如果您需要使用真实的(DBreal 类的实例)或假的(DBfake 类的实例)的 DB API,您的初始化可能看起来像if is_unit_test then this.dbapi = new DBfake else this.dbapi = new DBreal. (DBreal并且DBfake需要符合相同的接口,我们称之为DBapi。)
  3. 从您的测试方法的角度来看,第 2 步相当于(手动)依赖注入:该方法不知道哪个类实际实现了它的依赖(DB API)。相反,依赖项是从外部注入到方法中的。
  4. 在您的测试用例需要 DB API 的地方,他们使用this.dbapi
  5. 现在,您执行一个相同的测试类,其中设置了用于单元测试的标志,而没有设置用于集成测试的标志。(如何使标志可用取决于您的单元测试框架。)
  6. 显然,如果您在测试类中需要多个资源,则可以使用相同的方法。
  7. 有些人会发现if第 2 步中的显式很难看。为了使其更“优雅”,您可以使用控制反转(IoC) 容器(在 Java 中,例如 Spring 或 PicoContainer)来半自动化依赖注入。初始化将如下所示this.dbapi = myContainer.create(DBapi)
  8. 简单的情况下,一个 IoC 容器只会使事情复杂化,因为配置容器并非易事,涉及学习,打开新一类错误的可能性,并涉及附加文件。
  9. 然而,在更复杂的情况下,容器使事情变得更容易,因为如果创建资源还需要其他资源,容器也会处理它们的初始化,并且复杂性确实会降低。但除非你真的到达那里,否则我建议KISS
  10. 除非您有单独组装的重要原因,否则它们违反了 KISS。我建议先等待这个原因。

(请注意,有些人可能会告诉您,依赖注入仅在类级别进行。我认为这是毫无根据的教条主义。注入只是意味着调用者不知道它正在调用的确切类,无论它如何获得对象。它在类级别应用时通常会变得更有用,但根据您的测试框架,这可能会使上述情况变得过于复杂。请注意,一些测试框架有自己的注入功能。)

于 2014-09-22T08:46:02.830 回答