|
|
1
4
你如何处理大的变化? 根据需要尽可能小。 有时重构有一个很大的表面,但在细节上是微不足道的。这些可以在相当大的步骤中完成。花太多的精力去打破它们将是浪费。 我认为xml库的更改属于这一类。你把XML放进去,然后得到一些表示。只要表示没有改变(从表示状态的图变为事件流),库切换就很容易。 大多数情况下,重构并不简单,必须被分解。问题是什么时候该迈出更大的一步,什么时候该迈出更小的一步。我的观察是,我不善于估计变化的影响。大多数软件都很复杂,你可能会认为它们的更改很容易管理,但接下来就要重新开始工作了。所以我从一开始就做了一些改变。但如果事情开始变得不可预测,我会把一切都退回去。我认为这种情况发生在十分之一的重构中。但这次会很难。你必须找出系统中不符合你期望的部分。现在必须把问题分成多个小问题。我一次解决一个问题,完成后再登记。(还原和拆分的多次迭代并不少见。) 如果在代码中更改XML解析器和表示,那么这肯定至少是两个独立的重构。 模拟测试 您正在使用模拟对象测试对象/层之间的通信协议。 整个模拟方法可以看作是一种通信模型,如 OSI model . 当x层被参数x调用时,它将用参数a和b调用z层。您的测试指定了这个通信协议。 与模拟测试一样有用,尽可能少的测试功能。最好的选择是基于状态的测试:设置fixture、调用被测系统、检查被测系统的状态和纯功能(如在功能编程中)测试:用x调用返回a。 尝试以一种大多数功能都是松散耦合的方式设计系统。有些功能必须通过模拟测试来测试(完全分离的系统是无用的)。 集成测试不是测试系统的选项。它们只应用于测试系统的各个方面,这些系统可以随着多个单元的集成而中断。如果您尝试用集成测试测试您的系统,您将进入排列赌场。 所以你的gui测试策略应该很清楚。不能单独测试的gui代码部分应该使用模拟测试进行测试(当按下此按钮时,用参数y调用服务x)。 数据库把水弄脏了。不能模拟数据库,除非要重新实现要支持的每个数据库的行为。但这不是一个单元测试,因为您正在集成一个外部系统。我用这个概念性的问题解决了问题,把DAO和数据库看作一个不可分割的单元,可以用基于状态的测试方法进行测试。(不幸的是,这个单元在甲骨文日的表现与mysql日不同。它可能会在中间裂开,告诉你它不能自言自语。) |
|
|
2
3
这是我的方法:对于数据库访问层(dal),我 不要使用mock 为了我的单元测试。相反,我在一个真实的数据库上运行测试,尽管它与生产数据库不同。所以从这个意义上说,我不在数据库上运行单元测试。对于nhibernate应用程序,我使用相同的模式维护两个数据库,但数据库类型不同( ORM 这很简单)。我用 sqlite 对于我的自动化测试,和一个真正的my sql或sql server数据库进行即席测试。
只有一次我用模拟来测试DAL,那时我使用强类型数据集作为ORM(一个大错误!)我这样做的目的是
Typemock
给我一本完整表格的仿制品,这样我就可以表演了。
至于图形用户界面, 这是可能的 对gui交互进行单元测试。我这样做的方式是使用 MVP pattern 将模型、视图和演示者分开。实际上,对于这种类型的应用程序,我只在演示者和模型上进行测试,在模型中使用typemock(或者 dependency injection 隔离不同的层,这样我只能集中一层。我不测试视野,但我 做 测试演示者(大多数交互和错误都发生在这里)很多。 |
|
|
3
2
我的2美分…
|
|
|
4
1
在处理大的案件方面…tdd的目的是测试代码的行为,以及代码如何与它所依赖的服务交互。如果您想使用tdd,并且从dom解析器迁移到sax解析器,并且您自己编写sax解析器,那么您可以编写测试,根据已知的输入(即xml文档)验证sax解析器的行为。sax解析器可能依赖于helper对象的集合,这些对象实际上可以在最初被模拟出来,以测试sax解析器的行为。当您准备好为helper对象编写实现代码时,可以根据已知的输入围绕其预期行为编写测试。在sax解析器的示例中,您将编写单独的类来实现此行为,以免干扰依赖于dom解析器的现有代码。实际上,您可以创建一个IXMLParser接口,由DOM解析器和SAX解析器实现,这样您就可以随意将它们切换出去。 就使用mock或stub而言,使用mock或stub的原因是您对测试mock或stub的内部工作不感兴趣,但是您对测试依赖于mock或存根的内部工作感兴趣,而这正是您从单元角度真正测试的内容。如果您对编写集成测试感兴趣,那么您应该编写集成测试,而不是单元测试。我发现以tdd的方式编写代码对于帮助我定义代码的结构和组织(围绕我被要求提供的行为)非常有用。 我不熟悉任何现成的案例研究,但我确信它们都在那里。 |
|
|
5
1
我通常尝试分离我的业务逻辑、显示逻辑和数据库访问。我的大多数gui单元测试都涉及业务逻辑。下面是一个伪代码示例:
这确保了,不管我的数据库和gui代码有多糟糕,至少控制用户名更改的逻辑能够正常工作。如果将GUI代码组织成一组单独的控件(或小部件或窗体元素或它们在GUI框架中调用的任何内容),则可以以类似的方式对它们进行测试。 但最终,就像你所说的,这些单元测试并不能给你完整的描述。要做到这一点,您需要按照其他人的建议:创建一个具有“黄金集”数据的真实数据库,并对其运行集成/功能测试。但是,imo,这种测试不在tdd的范围内,因为设置它们通常非常耗时。 |
|
|
6
1
|
|
|
7
0
至于数据库角度,正如ngu soon hui提到的,您应该(imho)使用 DBUnit 它将在已知的配置中设置数据库(因此,您可以测试预期的结果),但它使用的是实际应用程序所使用的真实数据库。 对于较大的更改,我建议创建一个分支,并允许测试失败。这将为您提供一个需要更改的区域的todo列表,可以说这是tdd真正的亮点,甚至比使用小的、独立的函数更重要。 |
|
|
8
0
处理重大变化 以我的经验来看,这是比较少见的。当它们发生时,更新测试只是一个小麻烦。诀窍是为测试选择正确的粒度。如果测试公共接口,更新将很快进行。如果您测试私有实现代码,那么从sax更改为dom解析器将在很大程度上sax,您将感受到dom。;-) 测试gui代码 一般来说,我不会。我尽量保持我的ui层薄。这个想法是为了测试什么可能会坏。 测试数据库代码 如果可能的话,我更喜欢将数据访问代码放在接口后面,并在测试业务逻辑时模拟出来。正如其他人提到的,在某些时候,您可能希望对dal运行集成测试,以确保它在已知状态下对测试数据库工作。您可能需要对整个系统进行其他集成测试;拥有不同类型的测试层是一件好事。TDD主要是关于设计的,并不排除集成或验收测试的需要。 很有可能滥用mock和stub,编写只测试mock对象的测试。写好测试需要很多经验,我还在学习。 我的建议是继续练习tdd,也许最初是在较小的项目上。尽可能多地阅读它,与其他从业者交谈,并使用对你有用的东西。 持续集成确实有助于测试,因为它可以确保测试运行并使中断的测试可见。强烈推荐。 编辑:坦率地说,在很多情况下,我在分离数据访问代码时遇到了困难,最终使用的是test-deck数据库。即使像这样的集成测试也被证明是有价值的,尽管它们速度慢而且更脆弱。正如我所说,我还在学习。 |