为Fitnesse-20140630定制RestFixture代码
摘要:Fitnesse插件RestFixture在最新版Fitnesse输出测试结果为html文本,而非html。本博文记录RestFixture定制代码的过程。
准备开发环境
假定你已经正确安装JDK, Eclipse, Ant, Maven,安装步骤可以参见博文:
http://www.cnblogs.com/fitnessefan/p/3895706.html
Eclipse中用Git下载 git.oschina.net上的FitnesseKit源代码
https://git.oschina.net/fitneesefan/FitnesseKit.git
步骤: 
Eclipse Menu > Window > Open Perspective > Other… > Git > Clone a Git Repository and add it to this view:

克隆FitnesseKit到D:\git\FitnesseKit
编译并启动Fitneese
编译Fitneese
| 1 | D:\git\FitnesseKit\fitnesse >ant | 
编译RestFixture
| 1 | D:\git\FitnesseKit\RestFixture>mvn clean package | 
启动Fitneese
| 1 | D:\git\FitnesseKit\fitnesse >ant run | 
打开Fitnesse网站:
- 浏览器中输入: http://localhost:8001

添加测试wiki页
Fitnesse FrontPage页点击Edit按钮:

插入代码:
| 1 2 3 4 5 | 检查RestFixture是否已正确安装| RestFixtureInstallTest |百度地图服务API测试集| BaiduMapApiSuite | | 
点击Save:

上图中可以看到:
- RestFixtureInstallTest 是一个链接 http://localhost:8001/RestFixtureInstallTest ,因为我截图时该页面已存在了
- BaiduMapApiSuite 边上有一个 ? 指向链接:http://localhost:8001/BaiduMapApiSuite?edit&nonExistent=true
附带说明一下Fitnesse的wiki语法:
两个大写字母开头的英文单词(比如HelloWorld)连在一起,称为WikiWord,直接指向链接:http://localhost:8001/HelloWorld,如果该wiki页存在,就指向它,否则显示为一个”?“,并指向创建改wiki页的链接。
点击 RestFixtureInstallTest的链接,看到:

Edit后看到wiki文本为:
| 1 2 3 4 5 6 7 8 9 10 | !define TEST_SYSTEM {slim}!path D:\git\FitnesseKit\RestFixture\target\dependencies\*!path D:\git\FitnesseKit\RestFixture\target\smartrics-RestFixture-3.1-SNAPSHOT.jar!path D:\git\FitnesseKit\RestFixture\extra\slf4j-simple-1.6.6.jar| Table:smartrics.rest.fitnesse.fixture.RestFixture | http://www.w3school.com.cn || GET | /example/xmle/note.xml | 200| Content-Type: text/xml | //body[text()="Don't forget the meeting!"]| | 
点击Cancel,回到wiki页,
测试wiki页
点击Test运行测试:

输出测试结果为html文本,而非html
修改RestFixture代码直到测试结果显示为正常的html
分析测试结果
测试结果表格:
| Table:smartrics.rest.fitnesse.fixture.RestFixture | http://www.w3school.com.cn | |||
| GET | /example/xmle/note.xml | 200 | Content-Type: text/xml<br/><i><span class='fit_label'>expected</span></i><hr/><br/>Content-Length : 209<br/>Content-Type : text/xml<br/>Last-Modified : Mon, 29 Jul 2013 17:25:37 GMT<br/>Accept-Ranges : bytes<br/>ETag : "344628a4808cce1:28cc"<br/>Server : Microsoft-IIS/6.0<br/>X-Powered-By : ASP.NET<br/>Date : Sun, 03 Aug 2014 01:20:44 GMT<br/><i><span class='fit_label'>actual</span></i> | //body[text()="Don't forget the meeting!"]<br/><i><span class='fit_label'>expected</span></i><hr/><br/><?xml version="1.0" encoding="ISO-8859-1"?> <br/><!--  Copyright w3school.com.cn --> <br/><note> <br/>    <to>George</to> <br/>    <from>John</from> <br/>    <heading>Reminder</heading> <br/>    <body>Don't forget the meeting!</body> <br/></note>  <br/><br/><i><span class='fit_label'>actual</span></i> | 
Markdown语法不支持表格,只能从Fitnesse中把html文本直接贴到这里。
分析上面的表格,发现测试结果对原wiki内容作了替换:
- 第一行第一列(Table:smartrics.rest.fitnesse.fixture.RestFixture)被设置了绿色背景色
- 第二行第二列(/example/xmle/note.xml)被替换为<a>标签,能正确显示html。
- 第二行第四列(Content-Type:…)被替换为html文本,不能正确显示html。
*好像找到问题的线索了,对比一下第二行第二列为什么正确,而第二行第四列为什么不正确。
接下去笨办法:在所有文件中查找html字段:
Eclipse Menu > Search > Search… > File Search


接下去经过痛苦无助的人肉搜索,找到关键代码:

文件: D:\git\FitnesseKit\fitnesse\src\fitnesse\testsystems\slim\HtmlTable.java
| 1 2 3 4 | staticbooleanqualifiesAsHtml(String text) {    // performance improvement: First check 1st character.    returntext.startsWith("<") && HTML_PATTERN.matcher(text).matches();  } | 
函数名qualifiesAsHtml意思是可以当做html 
函数代码意思是必须以”<“开头且符合HTML_PATTERN定义的html匹配正则表达式
在HTML_PATTERN上按F3键,或者鼠标右键菜单中选择Open Declaration,可以看到HTML_PATTERN的定义:
| 1 2 3 4 | privatefinalstaticPattern HTML_PATTERN = Pattern.compile("^<(p|hr|pre|ul|ol|dl|div|h[1-6]|hgroup|address|"+          "blockquote|ins|del|object|map||video|audio|figure|table|fieldset|canvas|a|em|strong|small|mark|"+          "abbr|dfn|i|b|s|u|code|var|samp|kbd|sup|sub|q|cite|span|br|ins|del|img|embed|object|video|audio|label|"+          "output|datalist|progress|command|canvas|time|meter)([ >].*</\\1>|[^>]*/>)$", Pattern.CASE_INSENSITIVE | Pattern.DOTALL); | 
再回去看一下,测试结果表格:
- 第二行第二列(/example/xmle/note.xml)的html文本为: - <a href=“http://www.w3school.com.cn/example/xmle/note.xml”>/example/xmle/note.xml</a> 
- 第二行第四列(Content-Type:…)的html文本为: - Content-Type: text/xml<br/><i><span class='fit_label'>expected</span></i><hr/><br/>Content-Length : 209<br/>Content-Type : text/xml<br/>Last-Modified : Mon, 29 Jul 2013 17:25:37 GMT<br/>Accept-Ranges : bytes<br/>ETag : “344628a4808cce1:28cc”<br/>Server : Microsoft-IIS/6.0<br/>X-Powered-By : ASP.NET<br/>Date : Sun, 03 Aug 2014 01:20:44 GMT<br/><i><span class='fit_label'>actual</span></i> 
显然第二行第四列(Content-Type:…)不能被识别为html。
接下去,有两条路可走:
- 修改Fitnesse中的qualifiesAsHtml函数,直接return true。
- 修改RestFixture中测试结果,套一个<span> tag。
第1条路我试过,编译成功,但是编译后自动单元测试和验收测试时,报了无数个测试结果失败。 
主要原因是”<"和">“是有关键用处的,看下面Fitnesse验收用例:
http://fitnesse.org/FitNesse.SuiteAcceptanceTests.SuiteSlimTests.TestComparators

结果证明第1条路走不同,为了一个Fixture,更改Fitneese语法显然得不尝试。
接下去走第2条路:修改RestFixture中测试结果,套一个<span> tag
修改RestFixture代码
RestFixture实现为一个Slim TableTable,SlimTable的帮助文档在这里: 
接下去在Project RestFixture中搜索"pass:“,很容易定位到:
D:\git\FitnesseKit\RestFixture\src\main\java\smartrics\rest\fitnesse\fixture\SlimFormatter.java
| 1 | 102expected.body("pass:"+ Tools.makeContentForRightCell(expected.body(), typeAdapter, this, minLenForToggle)); | 
给测试结果套上一层<span> tag,把这一行修改为:
| 1 | 102expected.body("pass:<span>"+ Tools.makeContentForRightCell(expected.body(), typeAdapter, this, minLenForToggle) + "</span>"); | 
编译RestFixture:
| 1 2 3 4 5 6 7 8 9 10 | D:\git\FitnesseKit\RestFixture>mvn compile      ...[INFO] Compiling 1source file to D:\git\FitnesseKit\RestFixture\target\classes[INFO] ------------------------------------------------------------------------[INFO] BUILD SUCCESS[INFO] ------------------------------------------------------------------------[INFO] Total time: 25.678s[INFO] Finished at: 2014-08-03T13:13:07+08:00[INFO] Final Memory: 18M/64M[INFO] ------------------------------------------------------------------------ | 
编译生成一个新的class文件: SlimFormatter.class 
mvn compile命令没有生成新的smartrics-RestFixture-3.1-SNAPSHOT.jar
所以需要修改 http://localhost:8001/RestFixtureInstallTest
| 1 2 3 | !path D:\git\FitnesseKit\RestFixture\target\smartrics-RestFixture-3.1-SNAPSHOT.jar-->!path D:\git\FitnesseKit\RestFixture\target\classes | 
再次运行测试用例 http://localhost:8001/RestFixtureInstallTest:

耶!太完美了。
到此结束了吗?显然没有,接下去要执行 mvn package,打包生成smartrics-RestFixture-3.1-SNAPSHOT.jar。
修改单元测试代码并打包RestFixture
执行mvn package命令打包:
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | D:\git\FitnesseKit\RestFixture>mvn packageResults :...Failed tests:   shouldDisplayPassOnCheckIfExpectedAndActualMatch_whenDisplayingActual(smartrics.rest.fitnesse.fixture.SlimFormatterTest): (..)  shouldDisplayPassOnCheckIfExpectedAndActualMatch(smartrics.rest.fitnesse.fixture.SlimFormatterTest): (..)  shouldDisplayXmlDataInActual(smartrics.rest.fitnesse.fixture.SlimFormatterTest): (..)    ...Tests run: 264, Failures: 3, Errors: 6, Skipped: 0[INFO] ------------------------------------------------------------------------[INFO] BUILD FAILURE[INFO] ------------------------------------------------------------------------[INFO] Total time: 14.866s[INFO] Finished at: 2014-08-03T19:32:44+08:00[INFO] Final Memory: 18M/133M[INFO] ------------------------------------------------------------------------... | 
打包时,执行单元测试时,有3个测试失败。 
shouldDisplayPassOnCheckIfExpectedAndActualMatch_whenDisplayingActual函数在文件D:\git\FitnesseKit\RestFixture\src\test\java\smartrics\rest\fitnesse\fixture的第70行:
| 1 2 3 4 5 6 7 | publicvoidshouldDisplayPassOnCheckIfExpectedAndActualMatch_whenDisplayingActual() {    SlimCell c = newSlimCell("something matching logically abc123");    ...    assertThat(            c.body(),            is(equalTo("pass:something matching logically abc123<br/><i><span class='fit_label'>expected</span></i><hr/><br/>abc123<br/><i><span class='fit_label'>actual</span></i>")));} | 
按照之前代码的修改,pass:xxx应改成pass:<span>xxx</span> 
assertThat语句对应修改为:
| 1 2 3 | assertThat(            c.body(),            is(equalTo("pass:<span>something matching logically abc123<br/><i><span class='fit_label'>expected</span></i><hr/><br/>abc123<br/><i><span class='fit_label'>actual</span></i></span>"))); | 
再次执行mvn package,报告失败测试用例数为2个,说明修改正确。
继续修改另两个失败的测试用例,
- 执行mvn package,报0个失败,6个错误,BUILD FAILURE。
- 执行mvn clean package,报0个失败,0个失败,BUILD SUCCESS,smartrics-RestFixture-3.1-SNAPSHOT.jar生成了新版。
具体的修改内容可以到git中查看对应commit:
不知道什么原因,反正修改代码后,再次编译RestFixture时总是用mvn clean package就行了。
为Fitnesse-20140630定制RestFixture代码的更多相关文章
- 我的页面定制CSS代码(SimpleGamboge皮肤)
		我的页面定制CSS代码,针对博客园SimpleGamboge皮肤. 调整: 1.左上图片更换为自己的头像 2.扩大左侧栏宽度,缩小右侧主栏宽度宽度 3.扩大内容页面的评论区宽度,工具图标靠左 4.去广 ... 
- 页面定制CSS代码初探(一):页面变宽 文本自动换行 图片按比缩放
		初识博客 初写博客,先在设置里选了个喜欢的模板 第一眼就爱上了呢!那极简的风格,我喜欢!!但是,应用后,却发现... 纳尼!模板上右侧那张漂亮的图片呢?!我的怎么什么都没有.没有图片好难看啊,瞬间无爱 ... 
- 页面定制CSS代码初探(三):设置正文最小高度
		前言 没想到再次写这篇,已经过去1年半了. 现在审美也发生了改变,一开始做的样式全删了,只保留了h2的样式.原先认为界面要宽,两边留太多空很浪费,看惯了知乎和简书,觉得默认最大1000px的排版也不错 ... 
- 页面定制CSS代码初探(六):h2、h3 标题自动生成序号 详细探索过程
		前言 最近在整理博客写作格式的规范,碰到一个问题:标题要不要加序号? 直到我碰到一个人这么说 手动维护编号实在是一件很闹心的事情, 如果位置靠前的某个段落被删除了, 那么几乎每个段落的编号都要手动修改 ... 
- 页面定制CSS代码初探(五):给每篇文章最后加上'<完>'
		前言 我刚写博客的时候,有几篇是手动在最后加了个<完> 今天在看别人CSS布局时,发现很多::before和::after标签,因为没学过CSS,从名字看大概是前边/后边 加上某个东西的意 ... 
- 页面定制CSS代码初探(四):cnblogs使用Github引用样式
		前言 对于用惯了Github的人来说,眼里的引用应该是这样的 "Talk is cheap. Show me the code" -- Linus Torvalds 然而实际上cn ... 
- 页面定制CSS代码
		博客皮肤:SimpleMemory .catListTitle { margin-top: 21px; margin-bottom: 10.5px; text-align: left; border- ... 
- 页面定制CSS代码初探(二):自定义h2标题样式 添加阴影 添加底色 等
		故事的开始 先说一下<h2></h2>原先默认是空白的,很难看 然后今天无意中看到一个博友的标题很好看啊,一直就想要这种效果有没有? 好的东西自然要拿过来啦 通过审查元素,果然 ... 
- Fitnesse+RestFixture:Web服务回归测试利器
		RestFixture是Fitness的一个测试REST服务的插件,用于调用标准的http GET/POST等请求方法,并可以用XPath语法和Javascript语法检验http响应.本文介绍安装运 ... 
随机推荐
- cogs 自己出的题目 题解报告
			第一题很简单嘛,就是裸的动态树分治嘛 对于每一层的重心维护子树路径的信息和子树到上一层重心的点的信息 空间复杂度O(nlogn) 对于每一层我们按dis排序,之后记录军队数量的前缀和 查询的时候我们只 ... 
- 李洪强漫谈iOS开发[C语言-039]-剪刀石头布
			李洪强漫谈iOS开发[C语言-039]-剪刀石头布 
- lintcode :Binary Tree Preorder Traversal 二叉树的前序遍历
			题目: 二叉树的前序遍历 给出一棵二叉树,返回其节点值的前序遍历. 样例 给出一棵二叉树 {1,#,2,3}, 1 \ 2 / 3 返回 [1,2,3]. 挑战 你能使用非递归实现么? 解题: 通过递 ... 
- Matlab程序 转C++/Opencv基于Mat 不可不知的17个函数
			1.matlab中的imread相当于OpenCV中的cvLoadImage(imageName, CV_LOAD_IAMGE_ANYDEPTH | CV_LOAD_IMAGE_ANYCOLOR): ... 
- PowerDesigner中转换物理模型时的命名转换
			原文:PowerDesigner中转换物理模型时的命名转换 最近在使用PowerDesigner建模数据库,在使用中积累了一些遇到的问题和解决办法,记录下来,希望对遇到同样问题的朋友有所帮助. 早 期 ... 
- 32. Longest Valid Parentheses
			题目: Given a string containing just the characters '(' and ')', find the length of the longest valid ... 
- swift:高级运算符(位运算符、溢出运算符、优先级和结合性、运算符重载函数)
			swift:高级运算符 http://www.cocoachina.com/ios/20140612/8794.html 除了基本操作符中所讲的运算符,Swift还有许多复杂的高级运算符,包括了C语和 ... 
- Android IllegalStateException: The specified child already has a parent问题解决办法
			最近遇到一个很让人头疼的问题,使用viewpager动态添加页面或者删除页面时出现了问题(java.lang.IllegalStateException: The specified child al ... 
- 怎么在eclipse里调试WebDriver的源代码
			当你看完WebDriver的工作原理这篇博客以后,是不是也跃跃欲试想印证文章里的理论是不是正确,想自己也看下webdriver的源代码,并且调试下,通过代码来更深入的了解WebDriver的工作原理. ... 
- VC 6.0  LNK2005 错误 处理
			造成LNK2005错误主要有以下几种情况: 1.重复定义全局变量.可能存在两种情况: A.对于一些初学编程的程序员,有时候会以为需要使用全局变量的地方就可以使用定义申明一下.其实这是错误的,全局变量是 ... 
