WW.*_*WW. 28 integration-testing automated-tests unit-testing
最近我们一直在为现有的Java应用程序添加自动化测试.
我们有什么
这些测试中的大部分都是集成测试,可能会覆盖一堆调用,如: -
然后,我们验证servlet是否使用正确的XML进行响应,并且数据库中存在正确的行(我们的开发Oracle实例).然后删除这些行.
我们还有一些较小的单元测试,用于检查单个方法调用.
这些测试都是我们夜间(或adhoc)构建的一部分.
问题
这似乎很好,因为我们正在检查系统的边界:一端是servlet请求/响应,另一端是数据库.如果这些工作正常,那么我们就可以自由地重构或混淆其中的任何东西,并且有信心被测试的servlet继续工作.
我们可能会遇到哪些问题?
我看不出如何在单个类上添加更多单元测试会有所帮助.难道这不会让重构变得更难,因为我们更有可能需要抛弃并重新编写测试吗?
Cha*_*tin 34
单元测试更严格地定位故障.集成级别测试更符合用户要求,因此可以更好地预测交付成功.除非建造和维护,否则它们都不是很好,但如果使用得当,它们都非常有价值.
(更多...)
单元测试的事情是没有集成级别测试可以像一组好的单元测试一样运行所有代码.是的,这可能意味着你必须在某种程度上重构测试,但一般来说你的测试不应该如此依赖于内部.所以,举个例子说,你有一个函数来获得2的幂.你描述它(作为一个正式的方法人,我声称你指定它)
long pow2(int p); // returns 2^p for 0 <= p <= 30
Run Code Online (Sandbox Code Playgroud)
您的测试和您的规范看起来基本相同(这是一种伪xUnit用于说明):
assertEqual(1073741824,pow2(30);
assertEqual(1, pow2(0));
assertException(domainError, pow2(-1));
assertException(domainError, pow2(31));
Run Code Online (Sandbox Code Playgroud)
现在你的实现可以是一个带有倍数的for循环,你可以稍后出现并将其更改为shift.
如果你改变实现,比如它返回16位(记住sizeof(long)只保证不低于sizeof(short)),那么这个测试将很快失败.集成级别的测试可能会失败,但不是肯定的,并且它可能会在计算的下游某处不会失败pow2(28).
关键是他们真的测试不同的情况.如果你可以构建足够的细节和广泛的集成测试,你可能能够获得相同级别的覆盖率和细粒度测试的程度,但它可能很难做到最好,并且指数状态空间爆炸将打败你.通过使用单元测试对状态空间进行分区,您需要的测试数量会以指数方式增长.
Dav*_*ide 28
你在问两种不同的事物的利弊(骑马和骑摩托车有什么优点和缺点?)
当然两者都是"自动化测试"(骑行),但这并不意味着它们是替代品(你不骑马数百英里,而且你不骑摩托车在封闭的车辆泥泞中地方)
单元测试测试代码的最小单元,通常是一种方法.每个单元测试都与它正在测试的方法密切相关,如果它写得很好,那么它(几乎)仅与之相关.
它们非常适合指导新代码的设计和现有代码的重构.在系统准备进行集成测试之前很久就能发现问题.请注意,我编写了指南,所有测试驱动开发都是关于这个词的.
手动单元测试没有任何意义.
重构怎么样,这似乎是你最关心的问题?如果你只重构一个方法的实现(内容),而不是它的存在或"外部行为",单元测试仍然有效且非常有用(你无法想象在尝试之前有多大用处).
如果你更积极地重构,改变方法的存在或行为,那么是的,你需要为每个新方法编写一个新的单元测试,并可能扔掉旧的方法.可是我在写单元测试,特别是如果你的代码本身之前写出来,将有助于澄清设计(即什么样的方法应该做的,什么是不应该)而不被执行细节混淆(即怎样的方法应该做它需要做的事情).
自动集成测试测试代码的最大单元,通常是整个应用程序.
它们非常适合测试您不想手动测试的用例.但是您也可以进行手动集成测试,它们同样有效(只是不太方便).
今天开始一个新项目,没有单位测试没有任何意义,但我会说,对于像你这样的现有项目来说,为你已经拥有的所有东西编写它们并没有多大意义.
在你的情况下,我宁愿使用"中间立场"的方法写作:
事实上,你的集成测试只会确保你的"混乱"不起作用(因为一开始它不起作用,对吧?)但它不会给你任何线索
如果整个更改成功(并且答案将长期为"否"),集成测试将仅在最后给出确认.在重构过程中,集成测试不会给你任何帮助,这将使它变得更难并且可能令人沮丧.你需要单元测试.
Jam*_*ery 20
我同意Charlie关于集成级测试更多地反映用户操作和整个系统的正确性.我认为单元测试有更多的价值,而不仅仅是更严格地定位故障.单元测试比集成测试提供两个主要值:
1)编写单元测试既是设计行为也是测试.如果您练习测试驱动开发/行为驱动开发,编写单元测试的行为可帮助您准确设计代码应该执行的操作.它可以帮助您编写更高质量的代码(因为松散耦合有助于测试)并且它可以帮助您编写足够的代码以使测试通过(因为您的测试实际上是您的规范).
2)单元测试的第二个价值是,如果它们写得恰当,它们的速度非常快.如果我对项目中的某个类进行了更改,我可以运行所有相应的测试来查看是否有任何损坏吗?我如何知道要运行哪些测试?他们需要多长时间?我可以保证它会比编写良好的单元测试更长.您应该能够在几分钟内完成所有单元测试.
lav*_*nio 16
仅举几个个人经历的例子:
单元测试:
整合测试:
理想情况下两者都是必要的
例子:
单元测试:确保输入索引> = 0和<数组长度.外界时会发生什么?应该抛出异常还是返回null?
集成测试:输入负库存值时用户会看到什么?
第二个影响UI和后端.双方都可以完美地工作,你仍然可以得到错误的答案,因为两者之间的错误条件没有明确定义.
关于单元测试我们发现的最好的部分是它使开发人员从代码 - >测试 - >思考到思考 - >测试 - >代码.如果开发人员必须首先编写测试,那么他倾向于更多地考虑前面可能出现的问题.
回答你的最后一个问题,因为单元测试与代码的距离非常接近并迫使开发人员更多地预先考虑,实际上我们发现我们不会像往常那样重构代码,所以更少的代码被移动 - 所以不断折腾和编写新测试似乎不是问题.
这个问题肯定有一个哲学的部分,但也指出了务实的考虑.
用作成为更好的开发者的手段的测试驱动设计有其优点,但并不是必需的.许多优秀的程序员从未编写过单元测试.单元测试的最佳理由是它们在重构时为您提供的强大功能,尤其是当许多人同时更改源时.检查签入中的错误也为项目节省了大量时间(考虑转移到CI模型并建立在checkin而不是nightly上).因此,如果您编写单元测试,无论是在编写测试代码之前还是之后,您都可以确定在那一刻您编写的新代码.以后单元测试可以确保反对该代码会发生什么 - 这可能很重要.单元测试可以在完成QA之前阻止错误,从而加速您的项目.
如果正确完成,集成测试会强调堆栈中元素之间的接口.根据我的经验,集成是项目中最不可预测的部分.让单个部分工作往往不会那么难,但是将所有部分放在一起可能非常困难,因为在这一步骤中可能出现的错误类型.在许多情况下,由于集成中发生的事情,项目迟到了.在此步骤中遇到的一些错误可以在接口中找到,这些接口由于未在另一侧进行通信而在一侧进行了某些更改.集成错误的另一个来源是在开发中发现的配置,但在应用程序进入QA时会被遗忘.集成测试可以帮助显着减少这两种类型.
每种测试类型的重要性都可以争论,但对您来说最重要的是将这两种类型应用于您的特定情况.有问题的应用程序是由一小群人还是许多不同的团体开发的?您是否有一个存储库用于所有内容,或者每个应用程序的特定组件都有多个存储库?如果你有后者,那么你将面临不同版本的不同组件的相互兼容性的挑战.
每种测试类型都旨在揭示开发阶段不同集成级别的问题,以节省时间.单元测试驱动许多开发人员在一个存储库上运行的输出集成.集成测试(命名不佳)推动了堆栈中组件的集成 - 组件通常由不同的团队编写.集成测试暴露的问题类别通常更耗时.
如此务实,它真的归结为您自己的组织/流程中最需要速度的地方.
| 归档时间: |
|
| 查看次数: |
12578 次 |
| 最近记录: |