`
glinenator
  • 浏览: 1328 次
  • 性别: Icon_minigender_1
  • 来自: 上海
最近访客 更多访客>>
社区版块
存档分类
最新评论

TDD就一定要在实现前写好所有的Test Case?

阅读更多

 

今天做项目,和同事讨论一个细节的实现问题。纠结了很久,才发现在不改变原来设计的前提下,根本不可能实现这个细节需求。于是乎,改设计,改实现,这直接导致一批 UT 的修改甚至荒废,几天前 TDD 的很多努力都白做了。

 

事后思考原因,当初设计的缺陷是因为我们做了一个假设,在今天实现这个细节的时候,才发现这个假设根本不成立,而根本原因是设计的时候对需求的了解不够全面。这是谁的错?是设计人员的错吗?

 

我觉得没有谁能保证在实现前能把需求想得面面俱到,或者说,能保证自己设想的需求能 100% 准确。实际上,需求绝对不是在项目开始就定好的,需求也是随着项目的进展而不断演化的。所以,上面的设计人员实际上没错,这是常态。敏捷开发提倡拥抱变化,对于变化,我们不应该认为是谁错了,而应该感到高兴,说明我们的分析和设计越来越趋近于真实情况。我们应该时刻重构,时刻保证系统的松耦合和扩展性,这样就能积极响应变化。不过针对于今天的情况,我觉得仍然有可以改进的地方,就是 Test Case 的撰写。

 

对于 Test Case ,究竟应该什么时候写? TDD 都提倡在做设计的时候写,在代码实现之前写。这样做的好处是

1.       强迫我们在写代码前就仔细思考,并做出设计。水平高的程序员在写代码前都会先想好大概的设计,但是对于水平低的程序员往往没这个习惯。所以这是一个比较好的习惯,或者是管理手段。

2.       Test Case 来代替设计文档。

3.       在实现前写好 case ,会让程序员目标明确且充满动力地实现目标

4.       写好实现后,重构代码, Test Case 能够保证重构的正确性

 

但是通过这么长时间的实践,我也体会到设计的时候写 TC 也有弊端。那就是当需求调整,设计调整的时候,会导致之前写的 TC 白写,又有大量的修改和重写工作,而且这种事情经常发生。这直接导致了劳动力的浪费,也推迟了项目原型的快速实现。但是如果在需求都稳定后再写,我们又丧失了 TDD 带给我们的好处。应该怎么做呢?

 

我觉得可以尝试这样来做,简单的说,就是先写主要的TC,之后再补齐。在设计的时候,只针对每一个接口写一个 TC ,这个 TC 应该是考虑系统正常运行时的情况,而不用考虑边界条件(我觉得 TC 的繁多,其实大部分都是同一个接口的不同 case ,考虑了很多边界条件)。这样就照顾到了好处 1 、好处 2 、好处 3 。在功能都稳定后,再补齐所有的 TC ,这个时候的 TC 就应该全,考虑尽量多的情况。

 

不过这里有个问题,就是何时才是功能稳定?我的一个想法是,当实际运行效果出来,然后让 stake holders 看过满意后,才叫功能稳定。但是对于这个想法,我仍然有两点质疑:

1.       如果都要等到 stake holders 看过之后,我们才能写 TC ,这个回馈周期就会比较长。那在这个期间内我们做的重构,就没有 TC 的保障。难道要等到功能稳定, TC 都补齐之后才进行重构?这个显然不太合理。

2.       Stake holders 满意之后就能肯定功能稳定了吗? stake holders 看到的是操作流程界面上的效果,而往往一些阶段性成果都反映在后台数据里(比如今天的问题)。这个 stake holders 是很难察觉到的。

 

还需要在实践中继续摸索。

2
4
分享到:
评论
2 楼 glinenator 2011-03-19  
谢谢楼上的回答。

很同意楼上 TC只是保证“当前需求”正确实现的一种手段 这句话,但是不太同意TC在任何时候都是必要的观点。

我对于TC对自动化测试的作用是毫无怀疑的,怀疑在于何时写TC。

TDD强调在实现之前写TC,但是我认为在开发初期的时候,就把底层TC都写好,一是需求变动会比较大(或者初期设计就不完善),导致TC的大量回工,实际上前面写TC的努力就白做了;二是写TC要花大量的时间,特别是mock和stub的编写,这很明显地延迟了产品原型的交付。我们团队在开发一个功能的时候,写TC花的时间往往比写业务逻辑要多很多。而敏捷开发就是强调快速迭代,快速交付阶段性成果,快速得到反馈的。

所以我觉得TC,至少是大量的TC,在实现前都全部写好,是没有必要的。

楼上提到的BDD,我也有所了解,不过也不深,我的理解是它其实是一种function test,而非UT了。不知道事先用selenium写好case算不算BDD,这样高层的测试驱动开发,我觉得在实践中似乎不太靠谱,呵呵
1 楼 darkbaby123 2011-03-18  
其实关键还是一个度的问题,因为需求总是会变,测的越细,错的越多。维护测试的成本也越高。但这也不算是一种坏事,至少不会在你改了需求后对可能产生的bug一无所知。
我现在只是把TDD当作自动化测试的手段。其实想想,如果没有测试,可能我们需要开一个控制台或者SQL管理工具之类的,手动敲代码或者写SQL来看看数据是否正确。这种事情如果发生的很频繁,手动测试和自从测试所花的成本是等价的,甚至更多。
对于LZ最后的疑惑,其实大多数的情况下,功能永远也不可能“稳定”下来。TC只是保证“当前需求”正确实现的一种手段。这点在任何时候都是必要的,因为手动测试花费的成本更多(前提是你足够细致的手动测试)。
另一个办法就是现在某些人提倡的BDD。关注于行为而不是接口。不过我觉得从某种程度而言,它也是“不过多关注底层细节”的另一种诠释

相关推荐

    EmbedC_TDD__1 Keil中搭建自动化单元测试框架Unity

    在嵌入式软件开发中,测试驱动开发(TDD,Test-Driven Development)是一种重要的编程实践,它强调先编写测试用例,再根据测试用例编写功能代码。本主题将聚焦于如何在基于C语言的嵌入式环境,特别是在Keil IDE中,...

    TDD-change-case

    标题 "TDD-change-case" 指的是一个关于测试驱动开发(Test-Driven Development, TDD)的实践项目,特别是涉及到在不同数据格式之间转换的场景。在这个项目中,开发者将学习如何运用TDD方法来实现功能,比如在"蛇皮...

    GoogleTest1.7.0

    1. **测试用例(Test Case)**:在 GoogleTest 中,测试用例是一组相关的测试,通常对应于一个被测试的功能或模块。 2. **测试点(Test Point)**:每个测试用例由多个测试点组成,每个测试点验证特定的条件或行为...

    googletest-master_gtest_测试_

    它的设计基于测试驱动开发(TDD)的理念,鼓励开发者先编写测试,再实现功能。 **gtest的主要组件:** 1. **测试套件(Test Suite)**:测试套件是一组相关测试的集合,每个测试套件可以包含多个测试用例。 2. **测试...

    googletest

    `gtest`通过类来实现固定点,可以将这些共享资源封装在一个类中,然后在测试用例中使用。 5. **参数化测试**:`gtest`支持参数化测试,可以通过不同的输入参数运行同一个测试函数,这样可以更有效地覆盖代码的不同...

    googletest-master.zip

    《谷歌测试框架Googletest详解》 Googletest,又称为gtest,是Google公司开发的一款开源的C++...在`googletest-master`这个源码包中,你可以深入了解Googletest的内部实现和更多高级特性,进一步提升你的测试技能。

    googletest测试框架

    5. **测试驱动开发(TDD)**:gtest和gmock也支持测试驱动开发模式,鼓励开发者先写测试,然后编写满足测试的代码,确保每一步都符合预期。 6. **异常处理**:gtest支持对异常的断言,如`ASSERT_THROW`和`EXPECT_...

    TestDrivenDesign.ppt

    测试驱动设计(Test Driven Development,简称TDD)是一种软件开发方法,强调在编写实际的代码之前先编写测试。TDD的核心理念是“先写测试,后写代码”,旨在提高软件的质量、可维护性和设计的合理性。通过这种方法...

    trendyol-test-case

    标题“trendyol-test-case”暗示我们正在讨论与Trendyol相关的自动化测试案例,很可能是使用Selenium这一流行的Web自动化测试工具进行的。Trendyol是一家土耳其的电商平台,而“test case”通常指的是为了验证软件...

    bluebird-test-case

    在实际开发中,遵循测试驱动的开发(TDD)原则,先编写测试用例,再实现功能,能够确保代码的质量和稳定性。"bluebird-test-case"项目就是一个很好的实践示例,它为我们提供了一个学习和验证Promise和Bluebird功能的...

    googletest(2010)

    在`gtest`中,测试被组织为测试用例(Test Case)和测试点(Test)。每个测试用例可以包含多个测试点,每个测试点负责验证代码的特定行为。测试用例和测试点可以通过宏`TEST_F`来定义,并通过`main`函数中的`RUN_ALL...

    test-case

    在IT行业中,测试用例(Test Case)是软件开发过程中的关键组成部分,它详细定义了对软件进行测试的步骤、预期结果以及判断测试是否通过的标准。在这个“test-case”项目中,我们可以推测这是一个关于C#编程语言的...

    test:参考C ++单元测试框架(TDD,xUnit,C ++ 03111417)

    什么是Boost.Test?...编写您的第一个测试用例: BOOST_AUTO_TEST_CASE( your_test_case ) { std::vector<int> a{1, 2}; std::vector<int> b{1, 2}; BOOST_TEST( a == b ); } 建立并运行 完毕 功能强

    cpp-GoogleTestGoogleC测试框架

    - 可变环境:`SetUpTestSuite()`和`TearDownTestSuite()`则在所有测试用例开始前和结束后执行,适用于整个测试套件的初始化和清理。 4. **参数化测试** - Google Test支持参数化测试,允许一个测试用例根据一组...

    q-when-reduced-test-case:减少测试$ q.when时的测试用例

    4. **使用测试驱动开发(TDD)**:在编写新功能之前先写测试,这样通常会引导出简洁的代码结构,从而减少测试用例。 5. **组合测试**:通过创建代表多种情况的组合测试,可以减少重复的单个用例。 在`q-when-reduced-...

    CPPUNIT源码+配置及入门+使用示例代码.rar

    4. 固定的测试类结构:在CPPUNIT中,测试类通常继承自`cppunit::TestFixture`基类,并且包含一组`void setUp()`和`void tearDown()`方法,分别在每个测试用例开始前和结束后执行,用于初始化和清理工作。 5. 测试...

    gtest测试框架

    `gtest测试框架`是Google开发的一个C++单元测试库,全称为Google Test。它为C++程序员提供了一种...通过深入理解和熟练使用`gtest`,我们可以更好地遵循“测试驱动开发”(TDD)原则,提高代码质量,并减少回归错误。

    junit-master.zip

    《深入理解JUnit:Java单元测试框架的探索与实践》 JUnit是Java编程语言中最流行的单元测试框架之一...通过深入学习和实践,我们可以更好地掌握这个强大的框架,从而在开发过程中实现更好的测试驱动开发(TDD)实践。

    Unit Testing Training

    10. TDD(Test-Driven Development)和BDD(Behavior-Driven Development):这两种开发模式强调先写测试,再写实现,单元测试是TDD和BDD的重要组成部分。 通过深入学习和实践这个"Unit Testing Training"课程,...

Global site tag (gtag.js) - Google Analytics