关于测试驱动开发的哲学问题 [英] Philisophical Questions about Test-Driven Development

查看:23
本文介绍了关于测试驱动开发的哲学问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直对测试驱动的开发很感兴趣,但是当我在实际项目中尝试它时,我永远无法坚持下去.当我尝试时,我有几个哲学问题不断出现:

I have been perpetually intrigued by test-driven development, but I can never follow through with it when I try it on real projects. I have a couple of philosophical questions that continually arise when I try it:

  1. 你如何处理大的变化?在测试单个函数(一些参数、结果值、很少的副作用)时,TDD 是显而易见的.但是当你需要彻底检修一些大的东西时呢,例如从 SAX 解析库切换到 DOM 解析库?当您的代码处于中间状态时,您如何保持测试代码重构循环?一旦你开始改变,你会得到一堆失败的测试,直到你完全完成大修(除非你维护某种同时使用 DOM 和 SAX 的杂种类,直到你完成转换,但这很奇怪).在这种情况下,小步测试代码重构循环会发生什么?在整个过程中,您将不再以经过全面测试的小步骤移动.人们一定有办法处理这个问题.
  2. 在使用模拟测试 GUI 或数据库代码时,您真正在测试什么?Mocks 旨在准确返回您想要的答案,那么您如何知道您的代码将适用于真实世界的数据库呢?自动化测试对这种事情有什么好处?它在一定程度上提高了信心,但是 a) 它没有给你一个完整的单元测试应该给你的信心水平,并且 b) 在某种程度上,你不是简单地验证你的假设是否适用于你的代码,而不是您的代码是否适用于 DB 或 GUI?

谁能给我指出在大型项目中使用测试驱动开发的好的案例研究?令人沮丧的是,我基本上只能找到单个类的 TDD 示例.

Can anyone point me to good case studies on using test-driven development in large projects? It's frustrating that I can basically only find TDD examples for single classes.

谢谢!

推荐答案

你如何处理大的变化?

尽可能小.

有时重构有很大的表面,但在细节上却是微不足道的.这些可以通过相当大的步骤来完成.花太多精力试图分解它们将是浪费.

Sometimes refactorings have a big surface but are trivial in detail. These can be done in quite big steps. Putting too much effort in trying to break them down will be waste.

我认为 XML 库的更改属于这一类.您将 XML 放入并得到一些表示.只要您的表示不变(从表示状态的图形到事件流),库切换就很容易.

I would argue that a XML library change is in this category. You're putting XML in and get some representation out. As long as your representation does not change (from a graph representing the state to a event stream) the library switch is easy.

大多数时候重构不是微不足道的,必须分解.问题是什么时候做大步骤,什么时候做小步骤.我的观察是,我很不擅长估计变化的影响.大多数软件都足够复杂,您可能认为它们的更改很容易管理,但是整个细则必须再次运行.所以我确实从一些改变开始.但是,如果开始变得不可预测,我准备回滚所有内容.我会说这种情况发生在十分之一的重构中.但是这个会很难.您必须追踪系统中行为不符合您预期的部分.现在必须将问题分解为多个较小的问题.我确实一次解决一个问题,并在完成后进行检查.(还原和拆分的多次迭代并不少见.)

Most of the time refactorings are not trivial and have to be broken down. The problem is when to do bigger steps and when the smaller ones. My observation is that I'm quite bad at estimating the impact of a change. Most software is complicated enough that you may think they change is easily manageable but then there is the whole fine print that has to work again. So I do start with an amount of change. But I'm prepared to rollback everything if it starts to get unpredictable. I would say this happens in one out of ten refactorings. But this one will be hard. You have to track down the part of the system that does not behave as you expect. The problem has to be split now in multiple smaller problems. I do solve one problem at a time and check in when it's done. (Multiple iterations of revert and splitting are not uncommon.)

如果您更改代码中的 XML 解析器和表示,这绝对应该是至少两个单独的重构.

If you change the XML parser and representation in your code this should be definitely be at least two separate refactorings.

模拟测试

您正在使用模拟对象测试对象/层之间的通信协议.

You're testing a communication protocol between objects/layers with mock objects.

整个模拟方法可以看作是一种类似于 OSI 模型的通信模型.当 X 层作为参数 x 调用时,它将使用参数 a 和 b 调用 Z 层.您的测试指定了此通信协议.

The whole mock approach can be though of as a communication model like the OSI model. When layer X gets as call with parameter x it will call layer Z with parameters a and b. Your test specifies this communication protocol.

尽管模拟测试很有用,但使用它们测试尽可能少的功能.最好的选择是基于状态的测试:设置夹具、调用被测系统、检查被测系统的状态和纯函数(如在函数式编程中)测试:使用 x 调用返回 a.

As useful as mock test can be, test as few functionality with them as possible. The best option are state-based tests: setup fixture, call system under test, check state of system under test and pure functional (as in functional programming) tests: call with x returns a.

尝试以一种松散耦合的方式设计您的系统.某些功能必须通过模拟测试进行测试(完全解耦的系统是无用的).

Try to design your system in a way that most of its functionality is loosely coupled. Some of the functionality has to be tested with mock tests (a fully decoupled system is useless).

集成测试不是测试系统的选项.它们应该只用于测试可能因多个单元的集成而中断的系统方面.如果您尝试使用集成测试来测试您的系统,您将进入置换赌场.

Integration tests are no option to test your system. They should only be used to test aspects of the system that can break with the integration of multiple units. If you try to test your system with integration tests you'll enter into the permutation casino.

所以你的 GUI 测试策略应该很清楚.不能单独测试的 GUI 代码部分应使用模拟测试进行测试(按下此按钮时,服务 X 将使用参数 y 调用).

So your strategy for GUI testing should be clear. The parts of the GUI code that cannot be tested in isolation should be tested with a mock tests (when this button is pressed service X is called with parameter y).

数据库有点混乱.您不能模拟数据库,除非您要重新实现您想要支持的每个数据库的行为.但这不是单元测试,因为您正在集成外部系统.我已经解决了这个概念性问题,并将 DAO 和数据库视为一个不可分割的单元,可以使用基于状态的测试方法进行测试.(遗憾的是,与 mysql 日相比,该单元在拥有 oracle 日和 mysql 日时的行为有所不同.它可能会在中间中断并告诉您它无法自言自语.)

Databases muddy the water a bit. You cannot mock a database, unless you're going to reimplement the behavior of every database you would like to support. But this is not a unit test as you're integrating an external system. I've made peace with this conceptional problem and think of the DAO and database as one inseparable unit that can be tested with a state-based test approach. (Sadly, this unit behaves differently when it has its oracle day compared to its mysql day. And it may break in the middle and tell you that it cannot talk to itself.)

这篇关于关于测试驱动开发的哲学问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆