首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >了解一些单元测试实践

了解一些单元测试实践
EN

Stack Overflow用户
提问于 2012-06-05 07:14:45
回答 2查看 133关注 0票数 2

我是单元测试的新手--我只使用Testmethod做过基本的断言测试(我的最后一个模块,我创建了大约50个这样的模块)。

我目前正在阅读一本关于单元测试的书,书中的许多示例之一让我为每个单独的测试创建一个新类。下面是仅为一个测试用例创建的示例对象之一。我的问题是,有必要这样做吗?或者什么时候应该应用这种方法,什么时候不需要?

代码语言:javascript
复制
  public class and_saving_an_invalid_item_type : when_working_with_the_item_type_repository
    {
        private Exception _result;

        protected override void Establish_context()
        {
            base.Establish_context();

            _session.Setup(s => s.Save(null)).Throws(new ArgumentNullException());
        }

        protected override void Because_of()
        {
            try
            {
                _itemTypeRepository.Save(null);
            }
            catch (Exception exception)
            {
                _result = exception;
            }
        }

        [Test]
        public void then_an_argument_null_exception_should_be_raised()
        {
            _result.ShouldBeInstanceOfType(typeof(ArgumentNullException));
        }
    }
EN

回答 2

Stack Overflow用户

发布于 2012-06-05 07:27:12

您需要为每个单独的测试创建一个新类吗?我会说不,你当然不会。我不知道这本书为什么这么说,或者他们这样做只是为了帮助说明他们的例子。

为了回答你的问题,我建议对每组测试使用一个类……但它实际上要复杂一些,因为你如何定义“组”是不同的,并取决于你当时正在做的事情。

根据我的经验,一组测试实际上在逻辑上就像一个文档,它可以包含一组或多组测试,通过一些共同的方面将它们分组(有时是嵌套)在一起。测试面向对象代码的自然分组方式是先按类分组,然后再按方法分组。

下面是一个例子

1类的

  • 测试方法1的
    • 测试方法1的
      • 方法1的主要行为
      • 方法的替代行为

代码语言:javascript
复制
- tests for method 2 
    - primary behaviour of method 2
    - alternate behaviour of method 2

不幸的是,在C#或java (或类似的语言)中,你只能使用两层结构(而不是你真正想要的3层或4层),所以你必须修改一些东西来适应。

通常的方法是使用一个类将测试集分组在一起,而不是在方法级别对任何东西进行分组,如下所示:

代码语言:javascript
复制
class TestsForClass1 {
  void Test_method1_primary()
  void Test_method1_alternate()

  void Test_method2_primary()
  void Test_method2_alternate()
}

如果您的方法1和方法2都有相同的设置/拆卸,那么这是很好的,但有时它们不是这样的,导致这种崩溃:

代码语言:javascript
复制
class TestsForClass1_method1 {
  void Test_primary()
  void Test_alternate()
}

class TestsForClass1_method2 {
  void Test_primary()
  void Test_alternate()
}

如果你有更复杂的需求(假设你有10个method_1测试,前5个有设置要求X,接下来的5个有不同的设置要求),那么人们通常会像这样创建越来越多的类名:

代码语言:javascript
复制
class TestsForClass1_method1_withRequirementX {  ... }
class TestsForClass1_method1_withRequirementY {  ... }

这很糟糕,但是嘿-方形钉子,圆孔,等等。

就我个人而言,我喜欢在方法中使用lambda函数来提供第三级分组。NSpec展示了一个可以做到这一点的方法...我们有一个内部测试框架,略有不同,它读起来有点像这样:

代码语言:javascript
复制
class TestsForClass1 {
   void TestsForMethod1() {
      It.Should("perform it's primary function", () => {
         // ....
      });

      It.Should("perform it's alternate function", () => {
         // ....
      });
   }
}

这有一些缺点(如果第一个It语句失败,其他语句就不会运行),但我认为这种权衡是值得的。)

--问题最初是这样的:“真的有必要为我想要执行的每个测试创建一个对象吗?”根据这个解释,答案(大部分)是肯定的。

通常,单元测试涉及两个部分的交互

  • 正在测试的对象。通常这是你在环境中编写的
  • 类或函数的一个实例。通常,这是您传递给函数的任何参数,以及对象可能引用的任何其他依赖项。

为了使单元测试可靠,这两个部分对于每个测试都需要是“新鲜的”,以确保系统的状态是合理和可靠的。

  • 如果没有为每个测试刷新被测试的东西,那么一个函数可能会改变对象的内部状态,并导致下一个测试错误地失败
  • 如果没有为每个测试刷新环境,那么一个函数可能会改变环境(例如:在外部数据库中设置一些变量或其他东西),这可能导致下一个测试错误地失败。

显然,在许多情况下情况并非如此--例如,你可能有一个纯数学函数,它只接受整数作为参数,不接触任何外部状态,然后你可能不想费心重新创建测试下的对象或测试环境……但一般来说,任何面向对象的系统中的大多数东西都需要刷新,所以这就是为什么这样做是“标准实践”的原因。

票数 3
EN

Stack Overflow用户

发布于 2012-06-05 07:27:20

我不能完全遵循您的示例,但理想情况下,任何测试用例都应该能够独立于任何其他测试用例运行--真的,独立于任何其他测试用例。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/10889665

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档