你用单元测试测试什么?

时间:2009-02-05 21:19:48

标签: .net asp.net-mvc unit-testing tdd

这些天TDD似乎在每个人的嘴唇上,我自己尝试了一些,但我认为我没有得到这个想法。我正在研究如何编写单元测试,但我不明白我的单元测试应该测试什么。

  1. 如果我有一个返回数据列表的操作方法,我应该验证什么?只是视图名称是正确的,还是我应该验证数据?
  2. 如果我也要测试数据,我不会两次编写相同的代码吗?如果我使用相同的方法来检索我要比较的数据,那么测试数据的用途是什么?
  3. 我是否应该测试添加/编辑数据的方法?如何以正确的方式验证是否已添加/编辑/删除记录?
  4. 我知道这是一个很大的问题,但我没有因为在互联网上阅读文章而变得更聪明,因为他们似乎都关心如何进行测试,而不是什么

    作为一个例子 - 我有(或将要写)一个GuestbookController,其中包含查看,添加,编辑和删除帖子的方法。我需要测试什么?我该怎么做?

8 个答案:

答案 0 :(得分:26)

单元测试(UT)!=测试驱动设计(TDD)

这种混乱似乎相当普遍。 UT就是代码覆盖。 TDD关注功能。他们同样的事[抱歉Joel!]

使用UT,您可以编写任何您想要的代码,然后返回并测试每个函数(甚至是一些非常简单的函数)。

使用TDD,您可以选择下一个功能,然后首先为该功能编写测试。仅编写该功能的测试,测试覆盖率无关。您首先编写测试以强制制定接口决策。然后你编写代码来通过测试(记住'可能最有效的'最简单的事情')。然后根据您学到的内容重构代码。然后你继续下一个功能(大概是在办理登机手续并重新运行所有单元测试之后)。

如果需要,使用TDD进行开发,然后返回并使用UT工具完成覆盖。如果您要为开发人员创建类库或其他API,则测试覆盖率越高越好; - )

如果您只是编写应用程序来执行五项具体操作,那么仅TDD就足够了。

答案 1 :(得分:4)

我认为这里有一点Shu-Ha-Ri。你问的是一个难以解释的问题。只有在练习并努力应用TDD之后,才能获得什么。在那之前,我们会给你一些没有意义的答案,告诉你Monads Are Burritos的内容。这对你没有帮助,我们听起来像白痴(monad显然是柠檬雪纺派)。

我建议让Kent Beck的TDD book并通过它,然后练习。 “没有通往Ri的皇家之路。”

答案 2 :(得分:3)

测试您正在测试的模块接口的合同

  • 如果客户在使用您的课程时会发生特定行为,请对其进行测试。
  • 如果您的类应该阻止客户端的某些行为(如合同中所定义),请对其进行测试。

客户端是指使用您的班级的代码 根据预期的行为,我指的是返回值和对象状态的方法的预期结果。

将测试集中在逻辑(if,for,while等),因为像属性这样的扁平化东西失败的可能性较小,而不会被正常使用的应用程序捕获。

答案 3 :(得分:1)

这些是我认为对单元测试有用的通用指南:

1)识别边界对象(Win / WebForms,CustomControls等)。

2)识别控制对象(业务层对象)

3)确保至少为边界对象调用的控制对象公共方法写单元测试。

通过这种方式,您可以确保覆盖应用程序的主要功能方面(功能),并且不会冒微测试的风险(除非您想要)。

答案 4 :(得分:1)

在TDD中,您编写系统行为的规范并使用它们来驱动系统的设计。您为一个微小的行为编写一个测试,然后观察测试失败,然后编写代码以通过测试。通过定期重构,您始终保持代码质量尽可能高,以便更容易进行更多更改。

如何进行TDD的示例: http://butunclebob.com/ArticleS.UncleBob.TheThreeRulesOfTdd http://butunclebob.com/ArticleS.UncleBob.TheBowlingGameKata

另请参阅Writing standards for unit testing的答案 - 它有示例和链接以获取更多信息。以下是一些很好的链接:http://code.google.com/p/instinct/wiki/UsersGuide

答案 5 :(得分:0)

  1. 对于给定的输入或状态,您应该测试该方法的返回值是否符合您的预期。如果您的方法返回了大量类型的数据,则应验证它们是否正确。
  2. 在测试用例中使用一小组示例数据。不要从磁盘或数据库加载任何内容。传入一个字符串或在测试中构建测试对象。鉴于您希望从您的方法获得非常具体的结果的小数据集,您可以将其与实际结果进行比较。您希望避免在测试中为您计算值的代码,因为那时您必须为测试编写测试以确保它们正常工作!
  3. 测试您编写的每一段代码。对于添加记录(如果您的测试连接到测试数据库),您可以简单地查询最后插入的记录,或者比较前后记录的总数,并确保它增加1。如果你有一个模拟/存根框架,你可以跳过数据库并声明调用了保存数据库的方法。要测试编辑,只需再次从数据库中检索已编辑的记录,并断言该值已从其旧值更改。或者,如果模拟/存根,则正确调用了更改属性值的方法。
  4. 但实际上,要编写一些代码来测试即将编写。看它失败了。然后编写足够的代码使其通过。现在写另一个测试并重复。

答案 6 :(得分:0)

我认为您可以通过测试驱动开发/测试第一开发从单元测试中获得最大收益。您应该首先编写测试然后编写通过测试的代码。你应该先测试什么?

我觉得从用户故事中编写测试真的很有用。大部分时间我从开始用户故事开始编写自上而下的样式测试。例如我们的用户故事包含这样的任务:

  1. 当用户保存订单视图时应显示信息消息。
  2. 我通常从演示文稿/控制器层编写测试这个故事

      [Test]
        public void When_User_Save_Order_View_Should_Display_Information_Message()
        {
            using (mockRepository.Record())
            {
                repository.Save(order);
                view.Message= "Order saved successfully";
            }
    
            using (mockRepository.Playback())
            {
                presenter = new OrderSavePresenter(view, orderRepository);
                presenter.Save();
            }
        }
    

    然后我继续为我嘲笑或需要的每个类编写测试。

答案 7 :(得分:0)

我不打算测试简单的东西,比如吸气剂或定型器。您不需要测试编译器本身,因此在调用setter时检查值是否已分配是没有用的。

一般情况下,我尝试为具有实际代码的类的每个方法编写单元测试。这样,如果有人以后破坏了某个方法,它就会被捕获。

例如,有人更改了像“addElements(String [] elements)”这样的方法。他们试图使用“for(int i = 0; i< = elements.length; i ++)”。

,当单位测试在办理登机手续后运行时,抛出了超出范围的异常。

对于类似GuestBookController的东西,可能有离线测试的方法,但您可能需要实际建立与测试数据库服务器的连接。从那里,进行测试以添加帖子,编辑帖子和删除帖子,使用检索帖子的方法验证每个帖子发生的更改。

单元测试应该让您对代码的工作更有信心,并且当您进行更改时,它仍然有效。添加单元测试代码,直到您确信它已经过充分测试。在上面的示例中,您不必担心意外破坏留言簿。当您对代码进行更改时,单元测试确认您仍然可以添加,删除,编辑和检索帖子。