`
rocket
  • 浏览: 92438 次
  • 性别: Icon_minigender_1
  • 来自: 金城
社区版块
存档分类
最新评论

TDD:mock还是build

阅读更多

记得我以前写过一个文章是有关于4层web结构单元测试的,今天打算对TDD的环境问题重新讨论一下。

我当时的4层结构的单元测试时间上是从DAO到Service到Action再到JSP一种渐进测试,但是的想法是,先测DAO,那么Service对DAO的调用就有保证了,测试了Service,那么action调用service就有保证了。。。这样一层一层下来,我每层测试的目标也就达到了。这里其实我用了一个技巧,就是通过测试的顺序,来逐渐的构建了每层测试所需的外部环境。当然从这个角度来看,我当时使用的方法更贴近于集成测试了。

 

一般做TDD的时候最大的问题就是如何处理外部环境,这一般包括本身业务逻辑环境和技术框架环境。

 

在当前这个新项目中,我首先尝试对一个具体渲染器的测试方式就是用mock,这里用的是比较好用的easyMock。开始的时候觉得mock的方法很好用,但是当我发现我的待测方法中有多个需要mock的对象时(a.getX();b.getY();c.getZ())或者一个mock对象要通过多次级联获取时(如 a.getB().getC().getD().getE())就会发现mock的代价让你高到很不原意mock的地步。

 

而且当我们的框架却制造了一个让我无法逾越的障碍,就是我们对于manager(DAO)的调用都是用一个类的静态方法封装管理(比较奇怪为什么不用spring来进行管理呢)。这样静态方法就没法mock了,于是乎,要想测试就要采用build的方法了,就是你可以在你的testCase中事先通过已经实现好的DAO方法把需要使用到的业务对象真实的build出来,这样你就可以知道你的被测方法中通过dao调用到的数据究竟是什么了,于是就可以对你期望获得的结果和经过实际方法得到的结果进行对比验证了。
  看起来好像也是比较方便,但是实际上当你待测对象的业务模型,依赖于3-4级以上的相关模型时,你就会感觉到,这样build是一个代价非常高的事情。这种代价通常会让开发者丧失对TDD的兴趣了。

 

我发现其实在测试的时候我更加关注的是业务数据的build,而系统架构通常是服务于业务的。所以我就开始考虑,能否有个方法构建出最基本需要的业务模型数据呢。查阅了一些网上工具,发现没有能够满足我当前需求(kodo做持久层,还有我们自己研发的知识引擎),于是就自己简单做了一个InitialTestObject,想法很简单就是通过一个xml文件然后根据已知的业务模型结构定义好数据,然后根据固定的规则初始化好业务数据,并且存放到一个map中去(方法比较简单我就不列出源码了),然后再使用时把初始化放到setUp中去,这样在测试的时候就可以根据你的需要直接从map中获取到一个实际的业务对象用于测试的时候使用了,最后记得要在测试完成后要在tearDown中清除初始化的数据。这样处理后我发现在测试时就感觉到很方便了,用到什么直接从map中取就可以了。

 

也许有人会说这样做不还是是集成测试了吗,你build的时候需要数据库、持久层啊什么的,这里我不想来争论究竟是属于单元测试还是集成测试,因为它属于什么对于我们的功能来说是没有意义。无论什么测试的最终目标就是让我们的功能可用。

 

至于构建环境的实现我只是给出了一个对于我当前项目代价最小的方法,其实如果你的项目不是使用静态方法的话,可以考虑构建一个完全mock的环境这样就可以称之为单元测试了。
  而且对于这个InitialTestObject我觉得可以做成一个开源的小工具,支持各种不同的持久层(jdo,hibernate),然后根据我们定义的持久层模型做为我们的业务规则,就不需要自己编写具体的初始化规则代码了,你只需要写xml数据并指定好对应的持久层模型,希望大家可以对这个想法对提提建议,也许已经有人做了,那我就不做重复功了。

 

下篇预告:think in refactor         时间:待定

分享到:
评论
3 楼 daquan198163 2007-09-13  
没太看明白你的意思,似乎跟dbunit做的工作一样
2 楼 rocket 2007-09-13  
taowen 写道
mock对象会出现很多层次的时候,首先要考虑是不是对象设计上的问题。正常的建模,层次不会太深的。
但是的确会出现这样的问题,比如说写一个powerpoint的插件,powerpoint提供了一个shape->slide->presentation的树状层次。如果我们把这些对象都mock的话,就会出现非常深层次的expect。对于这样的问题,我的解决方案是手写stub。然后用state based的测试来做测试。
对于你说的持久层依赖的问题,你的领域对象就不应该依赖于DAO。正确的做法是像hibernate那样,用proxy模式来隔离持久化逻辑和业务逻辑。1
非常感谢你的建议,有些方法是我开始解决的时候没有想到的。
我开始的想法就是很简单,就是最快的解决mock代价的问题。
而stub的缺点就是对模拟的维护,有时候你会发现对于stub的维护甚至超过了待测的方法维护。
另外,对于proxy模式来隔离的方法确实应该是这样做,但是由于接手的系统结构已经是这样了,而且比较庞大所以这种改动代价会很高很高。

所以我现在看agile的时候是一种这样的想法,很多时候很多问题不是对不对,合不合适来看的,而是如何在代价和质量之间能够找到一个较好的平衡点。因为这样的平衡点将更为“可靠”一些。
1 楼 taowen 2007-09-13  
mock对象会出现很多层次的时候,首先要考虑是不是对象设计上的问题。正常的建模,层次不会太深的。
但是的确会出现这样的问题,比如说写一个powerpoint的插件,powerpoint提供了一个shape->slide->presentation的树状层次。如果我们把这些对象都mock的话,就会出现非常深层次的expect。对于这样的问题,我的解决方案是手写stub。然后用state based的测试来做测试。
对于你说的持久层依赖的问题,你的领域对象就不应该依赖于DAO。正确的做法是像hibernate那样,用proxy模式来隔离持久化逻辑和业务逻辑。1

相关推荐

    tdd-examples:Java 中的 TDD 示例

    标题 "tdd-examples:Java 中的 TDD 示例" 提供了一个关键的线索,即这个项目专注于使用测试驱动开发(Test-Driven Development, TDD)的 Java 编程实践。TDD 是一种软件开发方法论,它提倡在编写实际代码之前先编写...

    tdd-java-test:测试驱动开发示例

    在"Tdd-java-test-master"这个目录下,我们可能找到项目源码、测试用例以及相关的构建脚本,例如pom.xml(Maven项目配置文件)或者build.gradle(Gradle项目配置文件)。通过这些文件,我们可以了解项目的构建过程和...

    react-tdd-form:用TDD开发的带有API请求的表单|| 使用React,Jest,Testing-Library,Mock Service Worker和Material UI开发。 React JS课程的测试驱动开发(TDD)的练习

    带有API请求的TDD表格该表格是通过将测试驱动开发与 , , , 和 此练习是课程的一部分。 注意:模拟服务器和虚假的API请求已用于开发此练习。快速入门指南启动该项目的说明:前提条件该项目与 。 从开始指南。安装...

    library-api:使用Spring Boot和TDD(带有JUni5,Mock等)的RESTful项目

    library-api-main可能是项目的主目录,其中包含pom.xml(如果是Maven项目)或build.gradle(如果是Gradle项目),定义了项目的依赖关系和构建过程。 7. **Controller层**: Spring Boot应用中的Controller层负责处理...

    Test-Driven Development with Python [2017]

    Test-Driven Development with Python: Obey the Testing Goat: Using Django, Selenium, and JavaScript by Harry J. W. Percival ...Use TDD to build a REST API with a front-end Ajax interface

    Rhino.Mocks-3.6

    Rhino.Mocks是一个广泛使用的.NET单元测试框架,其版本3.6-Build-21提供了高效且用户友好的模拟(mocking)功能。这个框架主要适用于开发者进行单元测试时,需要模拟复杂的对象交互以隔离被测试代码。在本文中,我们...

    Mockito-Programming-Cookbook

    **Mockito** 是一个开源的 Java 测试框架,它被设计用于帮助开发者创建模拟对象(mock objects),以便于进行单元测试,支持 **Test-Driven Development (TDD)** 和 **Behavior Driven Development (BDD)** 的开发...

    BuildTools测试用例

    在敏捷开发环境中,测试用例经常被用来驱动开发(TDD,Test-Driven Development)和行为驱动开发(BDD,Behavior-Driven Development),确保代码质量从一开始就得到保障。 "BuildTools"通常是指一组自动化工具,...

    Mockit资料,自用

    在Gradle项目中,可以在build.gradle文件中加入: ```groovy testImplementation 'org.mockito:mockito-core:latest_version' ``` 然后执行构建命令,Mockito库就会被下载并引入到项目中。 三、Mockito基本用法 1. ...

    Test Driven Development with Python 2nd edition 2017 pdf

    By taking you through the development of a real web application from beginning to end, the second edition of this hands-on guide demonstrates...Use TDD to build a REST API with a front-end Ajax interface

    ASP.NET MVC Framework Unleashed(Stephen Walther)

    - **Test-Driven Development (TDD):** Apply TDD principles to improve the quality of your applications. - **Unit Testing and Mock Objects:** Create applications using unit testing and mock object ...

    测试驱动程序

    5. Mock对象与依赖注入:在TDD中,可能会使用Mockito等库来模拟依赖对象,以隔离被测试代码,确保测试的准确性。例如,`@InjectMocks`和`@Mock`注解可以用来创建和注入mock对象。 6. 编写可测试的代码:学习如何...

    Java Test Util

    这些工具以其合理的价格(在这里指的是“一积分”)和广泛适用性,赢得了广大开发者的喜爱,无论新手还是老手都能轻松上手。 在Java测试领域,有几个核心概念是必须了解的: 1. **单元测试**:单元测试是对软件中...

    Delphi-Mocks-master.zip

    - `build/`:构建脚本和其他构建相关的文件,用于编译和打包 Delphi-Mocks。 - `README.md`:项目介绍和使用说明,通常会包含安装和配置步骤。 - `LICENSE`:项目使用的开源许可协议,决定了你可以如何使用和分发...

    Springboot-junit项目源码

    - **起步依赖**:SpringBoot通过起步依赖来简化依赖管理,例如,通过在`pom.xml`或`build.gradle`文件中引入`spring-boot-starter-web`,即可自动包含Tomcat服务器和必要的Web依赖。 2. **JUnit介绍** - **单元...

    AndroidTesting:Android Testing Menggunakan Mockito和Espresso

    2. **测试驱动开发(TDD)**:在Kotlin环境中,Mockito和Espresso支持TDD实践,先编写测试,再编写实现代码,确保代码满足测试需求。 **项目结构** 在"AndroidTesting-main"目录下,你可能会看到以下结构: - `app`...

    Android单元测试的小例子

    8. **Testing Best Practices**:编写单元测试时,遵循一些最佳实践很重要,比如“测试单一职责”(每个测试方法只测试一个功能)、“先写测试再写代码”(TDD,Test-Driven Development)以及保持测试可读性和可...

    lib-test:pahakia 库的一些测试

    2. **Mock对象**:在进行单元测试时,为了隔离测试,开发者可能会使用Mockito等工具创建Mock对象,模拟Pahakia库与其他组件的交互,以便在孤立环境中测试目标功能。 3. **配置文件**:测试项目可能包含配置文件,如...

Global site tag (gtag.js) - Google Analytics