[oracle@OracleTest oracle]$ sqlplus log
SQL> connect / as sysdba
SQL> shutdown [immediate]
SQL> exit
2.停止Listener
[oracle@OracleTest oracle]$ lsnrctl stop
3.停止HTTP服务
[root@OracleTest /root]# service httpd stop
4.用su或者重新登录到root(如想重新安装可以保留oracle用户,省得输入环境变量了) 5.将安装目录删除
[root@OracleTest /root]# rm -rf /u01/oracle/
[root@OracleTest /root]# rm -rf /u01/oraInventory/
6.将/usr/bin下的文件删除
[root@OracleTest /root]# rm /usr/local/bin/dbhome
[root@OracleTest /root]# rm /usr/local/bin/oraenv
[root@OracleTest /root]# rm /usr/local/bin/coraenv
7.将/etc/oratab删除
[root@OracleTest /root]# rm /etc/oratab
8.将/etc/oraInst.loc删除
[root@OracleTest /root]# rm /etc/oraInst.loc
9.将oracle用户删除(若要重新安装,可以不删除)
[root@OracleTest /root]# userdel –r oracle
10.将用户组删除(若要重新安装,可以不删除)
[root@OracleTest /root]# groupdel oinstall
[root@OracleTest /root]# groupdel dba
11.将启动服务删除
[root@OracleTest /root]# chkconfig --del dbora
到此为止重启后,你的
Linux系统下的Oracle数据库已完全删除了!!!
以上是CentOS5.4+Oracle 11g的环境。
包括用户的登录脚本,数据库自动启动关闭的脚本,和Listener自动启动的脚本。
要是有可能连创建数据库的脚本也保存下来。
1.停止oepnfire服务
[root@openfire.clvn.com.cn ~]# su - openfire
-bash-4.1$ cd /usr/local/openfire/bin
-bash-4.1$ ./openfire stop
2.找到openfire配置文件
[root@openfire.clvn.com.cn ~]# cd /usr/local/openfire/conf/
[root@openfire.clvn.com.cn conf]# ls
available-plugins.xml crowd.properties openfire.xml security.xml server-update.xml
[root@openfire.clvn.com.cn conf]# vim openfire.xml
找到
<setup>true</setup>
将其删除
3.重新启动openfire
[root@openfire.clvn.com.cn ~]# su - openfire
-bash-4.1$ cd /usr/local/openfire/bin
-bash-4.1$ ./openfire start
Starting openfire
今天写个自动刷新页面的脚本,发现在启动firefox的时候,出现一个类似如下的错误:
请在文本框输入文字15:22:12.031 WARN - GET /selenium-server/driver/?cmd=getNewBrowserSession&1=*fir efox&2=http://www.google.com HTTP/1.1 java.lang.RuntimeException: Firefox refused shutdown while preparing a profile at org.openqa.selenium.server.browserlaunchers.FirefoxCustomProfileLaunc her.waitForFullProfileToBeCreated(FirefoxCustomProfileLauncher.java:277) |
后来查了google发现问题是selenium不支持高版本firefox, 解决方案如下:
1、用winrar打开selenium-server.jar;
2、查找两个目录:customProfileDirCUSTFFCHROME和customProfileDirCUSTFF;
3、搜索每个目录,对每个文件install.rdf,编辑如下行:
修改
<!-- Firefox --> <em:targetApplication> <Description> <em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id> <em:minVersion>1.4.1</em:minVersion> <em:maxVersion>3.5.*</em:maxVersion> </Description> </em:targetApplication> 为 <!-- Firefox --> <em:targetApplication> <Description> <em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id> <em:minVersion>1.4.1</em:minVersion> <em:maxVersion>3.6.*</em:maxVersion> </Description> </em:targetApplication> |
还可以改得更加大,那么就可以支持4.0 的firefox了
另外,在参数化时,对于一次压力
测试中均只能用一次的资源应该怎么参数化呢?就是说这些资源用了一次就不能在用了的。
--参数化时,在select next row选择unique,update value on选择 each occurence,
1. 迭代跟虚拟用户数没什么必然联系
迭代是这样的:
迭代1次 迭代2次 迭代3次
用户1 X1 X2 X3
用户2 Y1 X2 Y3
其中的X1-3 Y1-3是参数,参数规则就是二楼说的
这么两个用户是根据你的rump up 上来的,比如5秒上两个用户,那么用户1和2就在5秒之内加载进来的,不知道说清楚了没。
第二个问题就简单了,只能用一次的参数,首先确保你的参数足够,另外规则选择的时候,注意选择唯一
迭代次数只是对你设置了迭代次数的action进行迭代,而用户数可以理解为对整个录制过程的迭代(只是各个用户不同) 而且增加并发量可以通过增加用户来达到 还可以设置集合点来增加某个操作的并发量
假如一个脚本,设置最大并发量为10,每5秒中增加2个并发用户,而Action设置的迭代为10次:
当开始至2秒时,加载了2个用户,这2个用户分别开始运行,并都运行10次,不管这个2个用户运行10次是否结束,当下一个2两秒到来时,即开始至第4秒时又加载了2个用户,这2个又运行10次;就这样一直加载到10个并发用户,然后当每个用户都运行完10次时就结束。
这样中间最大并发是10个,但不一定能达到10个,因为在加载最后几个时,前面的有可能已经运行结束,所以如果要真正达到最大并发10就必须设置集合点来完成
不过也不一定非要设置集合点才能实现同时处在running的状态有10个用户。
设置duration也是可以的。不过那就不只每个用户运行10次了。
如果想实现用户迭代10次,并且想同时running为10个用户,就应该设置集合点。
迭代(Iterate)设计,或者我们称之为增量(Incremental)设计的思想和XP提倡的Evolutionary Design有异曲同工之妙。
注意:1、 参数类型:在创建参数的时候,我选择了参数类型为File。参数类型共有9 种,现在来简单介绍一下所有的参数类型以及意义。
1.1、 DateTime:在需要输入日期/时间的地方,可以用 DateTime 类型来替代。其属性设置也很简单,选择一种格式即可。当然也可以定制格式。
1.2、 Group Name:很少用到。在实际运行中,LoadRunner 使用该虚拟用户所在的Vuser Group 来代替。但是在 VuGen 中运行时,Group Name将会是None。
1.3、 Load Generator Name :在实际运行中, LoadRunner 使用该虚拟用户所 在LoadGenerator 的机器名来代替。
1.4、 Iteration Number :在实际运行中,LoadRunner 使用该测试脚本当前循环的次数来代替。
1.5、 Random Number:随机数。很简单。在属性设置中可以设置产生随机数的范围。
1.6、 Unique Number:唯一的数。在属性设置中可以设置第一个数以及递增的数的大小。
注意:使用该参数类型必须注意可以接受的最大数。例如:某个文本框能接受的最大数为99。当使用该参数类型时,设置第一个数为 1,递增的数为1,但100个虚拟用户同时运行时,第100 个虚拟用户输入的将是 100,这样脚本运行将会出错。这里说的递增意思是各个用户取第一个值的递增数,每个用户相邻的两次循环之间的差值为 1。举例说明:假如起始数为 1,递增为 5,那么第一个用户第一次循环取值 1,第二次循环取值 2;第二个用户第一次循环取值为 6,第二次为 7;依次类推。
1.7、 Vuser ID:设置比较简单。在实际运行中,LoadRunner 使用该虚拟用户的 ID 来代替,该 ID 是由 Controller 来控制的。但是在 VuGen 中运行时,Vuser ID 将会是 –1。
1.8、 File:需要在属性设置中编辑文件,添加内容,也可以从现成的数据库中取数据
1.9、 User Defined Function:从用户开发的 dll 文件提取数据。
用HTTP协议录制了一个包含登录、浏览、退出过程的脚本,录制时都放到Action部分,这时脚本设置了迭代后可以多次重复运行,但是出于处理逻辑,一旦将登录脚本放到Init部分后,就无法正常进行迭代运行了。今天专门找个时间做了尝试,发现可能出现这两种错误。
1、这是我犯的一个低级错误。在我将登录脚本移到Init部分时,将登录脚本之后的浏览操作前面的web_reg_find脚本也一起移了过去,结果运行完Init部分脚本就出错了。错误提示:
Error -27259: Pending web_reg_save_param/reg_find/create_html_param[_ex] request(s) detected and reset at the end of the Init section
这种错误的现象是没有进行迭代已经出错了,错误提示也很明确。这时只要把web_reg_find放回Action部分的正确的位置即可。
2、单次运行正确,但是多次迭代运行时出错,错误提示:
Error -27985: There is no context for HTML-based functions. A previous function may not have used "Mode=HTML" or downloaded only non-HTML page(s), or the context has been reset (e.g., due to a GUI-based function)
这种错误可能比较常见,原因是在Runtime Settings的Browse Emulation中设置了Simulate a new user on each iteration引起的。由于这个设置导致每次迭代时都会模拟一个新的用户,此时这个新的用户并没有执行init操作而失败了,也即是错误提示中的There is no context。
这里涉及到一个知识点就是在Rumtime Settings的迭代设置中,迭代运行次数只对Action部分有效,而Init部分和End部分还是只运行一次的。这时如果设置了“Simulate a new user on each iteration”,将出现上面的第2种错误。
一、概述
目前,持续集成已成为当前许多
软件开发团队在整个软件开发生命周期内侧重于保证代码质量的常见做法。随着
测试的自动化率逐步提高,每天要需要自动执行的
测试用例也就越来越多了,当我们发现,跑一次完整的测试需要几个小时,测试的速度已远远跟不上编译的速度的时候,我们自然要考虑如何加快测试的速度了——分布式执行测试用例,显然是一个不错的办法,本文正是讲述如何利用Hudson来实现
自动化测试的分布式执行。
二、基本概念
1.什么是持续集成
简而言之,持续集成(Continuous Integration)是一种软件开发实践,即团队开发成员经常集成它们的
工作,通常每个成员每天至少集成一次,也就意味着每天可能会发生多次集成。每次集成都通过自动化的构建(包括编译,发布,自动化测试)来验证,从而尽快地发现集成错误。
持续集成可以帮助我们做到:
1. 软件构建自动化
2. 持续自动的构建检查
3. 持续自动的构建测试
4. 构件生成后续过程的自动化
关于持续集成的更多概念和知识,本文不做深入阐述,有兴趣的读者可以参考以下链接:
2.关于Hudson
没错,Hudson正是一个能帮助我们实现持续集成的平台。确切来说,Hudson是一个可扩展的持续集成引擎。 主要用于:
1. 持续、自动地构建/测试软件项目
2. 监控一些定时执行的任务
更多关于Hudson的介绍和说明,请参考以下链接:
持续集成工具Hudson
三、分布式测试
1.串行执行测试
一般,我们会在Hudson上配置三个任务,分别是编译任务、快速测试任务、慢速(完整)测试任务。这三个任务一般是顺序串行执行的,上一个任务执行完毕了之后,下一个任务才能开始执行。
2.化整为零
串行执行测试,当需要运行的自动化测试用例较多时,任务执行的速度显然不会让我们满意,尤其是完整测试任务。如何加快执行速度呢 我们首先会想到的是,可以化整为零,把slowtest任务(完整测试任务)分成多个小任务,这样,就可以在多台机器上同时执行,从而加快执行速度了。
然而,这样的做法,缺点也很明显——测试结果也被拆分,而且维护成本较高:
①slowtest的测试结果被拆分到各个小任务里,测试结果不方便统一显示和分析。
②为达到最大速度,需要我们人工来把slowtest任务拆分成跟已有测试机器数量相等的测试任务,如果测试机器的数量新增或减少了,就需要我们再次人工调整任务。
③需要我们人工来指定不同的测试用例,平均分给各个测试任务,如果测试用例数量发生变化,也需要我们再次调整设置。 3.分布式执行!
一般的任务,是不能并发调度执行的,有多个构建请求时,即使有多个测试机器是空闲的,也必须按时间顺序,一个接一个运行,典型的情况如下图所示。
因此,上述化整为零的做法把slowtest任务拆分为多个子任务,从而达到多个任务同时可以同时执行的效果。
实际上,要加快自动化测试的速度,不一定需要多个任务同时执行——我们只需要多个构建同时执行。Hudson任务设置里有一个选项
可以设置任务是否可以多个构建同时执行。我们把这个选项勾选上后,当同时有多个构建请求时,只要有N个测试机器是空闲的,那就可以有N个构建同时执行!
4.远程控制
Hudson可以设置一个任务构建完成后自动触发另外的任务构建。这样,编译任务、快速测试任务、完整测试任务可以自动地有序执行。然而,这样的自动触发任务构建,上游任务只能对每个下游任务触发一次。那么,当我们的quicktest任务构建完毕后,如何触发多个slowtest任务构建呢 难道只能手工在网页页面上点击“立即构建”吗
当然不是。在Hudson任务设置里,如下图,有这样的一个设置,勾选并填写”Authentication Token”上之后,我们就可以使用这个Token编写脚本或程序来随时触发一个任务的构建了。
例如,用类似以下的Python代码,就可以触发一次”Your_Job”任务的一次构建。
如果”Your_Job”任务是带参数(见后文)的,可以用类似以下的代码触发一次构建。
5.测试用例分配
为了让slowtest任务的每一次构建能执行不同的自动化测试用例,我们需要指定该任务为带参数的任务,在任务设置中勾选
并指定相应的参数。例如,我们指定一个字符串参数名为suite,用于指定某一次构建是运行哪一个suite里的case。这样,在具体的某一次构建中,suite会以环境变量的方式存在。当然,如果构建的时候没有指定suite参数,那么suite就会默认为None。
这样,在一个任务的每次构建中,就可以根据环境变量suite的值去取不同的测试用例来运行了。
6.测试结果回收
当分布式测试执行完毕后,slowtest的测试结果仍然被拆分到了多个构建之中,如何把这些测试结果统一收集起来呢
例如,我们很可能需要把所有测试用例的运行生成的JUnit格式的测试结果报表合并在一起,即我们需要收集slowtest任务每一次构建所产生的xml测试结果文件。
解决办法是,我们在slowtest任务里设置Hudson把我们需要的一些文件在构建完成后打包存档起来。例如下图这样设置,则Hudson在每一次构建完成后,会将test_report文件夹下的所有xml文件上传至服务器保存下来。
这样,我们也就可以自己编写脚本或程序去获取这些文件了。例如,类似如下Python代码,可以获得test-slowtest任务第67次构建所生成的所有文件,打包保存为tmp.zip。
SQL注入攻击是黑客攻击网站最常用的手段。如果你的站点没有使用严格的用户输入检验,那么常容易遭到SQL注入攻击。SQL注入攻击通常通过给站点
数据库提交不良的数据或查询语句来实现,很可能使数据库中的纪录遭到暴露,更改或被删除。
为了防止SQL注入攻击,PHP自带一个功能可以对输入的字符串进行处理,可以在较底层对输入进行安全上的初步处理,也即Magic Quotes。(php.ini magic_quotes_gpc)。如果magic_quotes_gpc选项启用,那么输入的字符串中的单引号,双引号和其它一些字符前将会被自动加 上反斜杠\。
但Magic Quotes并不是一个很通用的解决方案,没能屏蔽所有有潜在危险的字符,并且在许多服务器上Magic Quotes并没有被启用。所以,我们还需要使用其它多种方法来防止SQL注入。
许多数据库本身就提供这种输入数据处理功能。例如PHP的
MySQL操作函数中有addslashes()、 mysql_real_escape_string()、mysql_escape_string()等函数,可将特殊字符和可能引起数据库操作出错的字 符转义。那么这三个功能函数之间有什么却别呢?下面我们就来详细讲述下。
虽然国内很多PHP程序员仍在依靠addslashes防止SQL注入,还是建议大家加强中文防止SQL注入的检查。addslashes的问题在 于黑客 可以用0xbf27来代替单引号,而addslashes只是将0xbf27修改为0xbf5c27,成为一个有效的多字节字符,其中的0xbf5c仍会 被看作是单引号,所以addslashes无法成功拦截。
当然addslashes也不是毫无用处,它是用于单字节字符串的处理,多字节字符还是用mysql_real_escape_string吧。
另外对于php手册中get_magic_quotes_gpc的举例:
if (!get_magic_quotes_gpc()) { $lastname = addslashes($_POST[‘lastname’]); } else { $lastname = $_POST[‘lastname’]; } |
最好对magic_quotes_gpc已经开放的情况下,还是对$_POST[’lastname’]进行检查一下。
再说下mysql_real_escape_string和mysql_escape_string这2个函数的区别:
mysql_real_escape_string 必须在(PHP 4 >= 4.3.0, PHP 5)的情况下才能使用。否则只能用 mysql_escape_string ,两者的区别是:mysql_real_escape_string 考虑到连接的当前字符集,而mysql_escape_string 不考虑。
总结一下:
* addslashes() 是强行加\;
* mysql_real_escape_string() 会判断字符集,但是对PHP版本有要求;
* mysql_escape_string不考虑连接的当前字符集。
dz中的防止sql注入就是用addslashes这个函数,同时在dthmlspecialchars这个函数中有进行一些替换$string = preg_replace('/&((#(\d{3,5}|x[a-fA-F0-9]{4}));)/', '&\\1',这个替换解决了注入的问题,同时也解决了中文乱码的一些问题
本文总结一下平时经常使用的
SQL语句以及一些ORACLE函数的微妙之处。欢迎大家多多补充平时最常用的SQL语句,供大家
学习参考。
SQL> select * from temp2; NAME SORCE ---------- ---------- 1 43 2 23 3 42 4 87 5 12 <span style="font-size: 14px;"><strong><span style="color: #ff0000;">1、数据累加</span></strong></span> SQL> SELECT NAME, sum(sorce) OVER(ORDER BY NAME) 2 FROM temp2 3 ORDER BY NAME; NAME SUM(SORCE)OVER(ORDERBYNAME) ---------- --------------------------- 1 43 2 66 3 108 4 195 5 207 <span style="font-size: 14px;"><strong><span style="color: #ff0000;">2、去掉最大值和最小值</span></strong></span> SQL> SELECT NAME, 2 sorce, 3 LAG(sorce) over(order by sorce) Lag_List, 4 LEAD(sorce) over(order by sorce) Lead_List 5 FROM temp2; NAME SORCE Lag Lead ---------- ---------- ---------- ---------- 5 12 23 2 23 12 42 3 42 23 43 1 43 42 87 4 87 43 |
1、著名分析函数--排序
SQL> SELECT name, 2 value, 3 RANK() OVER(order by value) RANK_SORT, 4 DENSE_RANK() OVER(order by value) DENSE_SORT, 5 ROW_NUMBER() OVER(order by value) ROW_SORT 6 FROM sorce; NAME VALUE RANK_SORT DENSE_SORT ROW_SORT ---------- ------ ---------- ---------- ---------- wu 21 1 1 1 zhang 60 2 2 2 Li 70 3 3 3 xue 119 5 5 5 <span style="color: #ff0000;">wang 130 6 6 6 chen 130 6 6 7 sun 175 8 7 8</span> zhao 285 9 8 9 su 359 10 9 10 Li 480 11 10 11<br> |
可见三者的区别:<br>RANK()OVER():如果值相同,则两者顺序号相同,随机一个在另外一个的上边,而且顺序号会有间断,不是连续的;<br>DENSE_RANK():如果值相同,则两者顺序号相同,随机一个在另外一个的上边,而且顺序号仍然是连续的,不存在断层的现象;<br>ROW_NUMBER():如果值相同,则两种顺序号不同,安装顺序号依次排开,而且顺序号是连续的。
2、TRANSLATE()函数
translate函数与replace类似,但是又与replace不同,translate指定字符串string中出现的from_str,将from_str中各个字符替换成to_str中位置顺序与其相同的to_str中的字符。
SQL Reference中给的例子:SELECT TRANSLATE('SQL*Plus User''s Guide', ' */''', '___') FROM DUAL;
巧用:
(1)判断一个字符串是数字
SELECT TRANSLATE('ABC123','#1234567890.','#') FROM DUAL;
(2)统计字符E出现的次数
SELECT LENGTHB(TRANSLATE('ABCDEFGEFGDBE','E'||'ABCDEFGEFGDBE','E')) FROM DUAL;
3、ROUND()函数
我们平时用得最多的是第一种,用ROUND()函数作为数据四舍五入运算,其实ROUND函数还有第二种形式,对日期进行格式化操作,与TRUNC()函数类似。
如:SELECT ROUND(SYSDATE,'yyyy') FROM DUAL;
SELECT ROUND(SYSDATE,'MM') FROM DUAL;
SELECT ROUND(SYSDATE,'HH24') FROM DUAL;
4、NVL相关函数
NVL相关的函数有:NVL(expr1,expr2),NVL2(expr1,expr2,expr3),NULLIF(expr1,expr2),DECODE(expr1,expr2,value1,expr3,value2...,default)
(1) NVL(expr1,expr2) :如果expr1为空,则用expr2来替换。
(2) NVL2(expr1,expr2,expr3) :如果expr1非空,则返回expr2,否则返回expr3。
(3) NULLIF(expr1,expr2):将expr1和expr2做比较,如果想等,则返回null,否则返回expr1。
(3) DECODE(expr1,expr2,value1,expr3,value2...,default):如果expr1与expr2相等,则返回value1,如果expr1与expr3相等,则返回value2,...否则,返回default。
5、收集表的统计信息
收集表的统计信息方法有很多种: (1) ANALYZE (2) DBMS_STATS
看起来很繁琐,其实用起来挺简单的。
如对某张表进行分析:
ANALYZE TABLE TABLE_NAME COMPUTE STATISTICS;
目前,ORACLE官方推荐第二种方法。在DBMS_STATS包里有很多过程和方法,对SCHEMA、TABLE和INDEX进行收集统计信息相关的操作。
EXEC DBMS_STATS.GATHER_TABLE_STATS(OWNNAME=>'SCOTT',TABNAME=>'EMP',DEGREE=>4,CASCADE=>'TRUE');
一、JSON
JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式。 JSON采用完全独立于语言的文本格式。这些特性使JSON成为理想的数据交换语言。易于人阅读和编写,同时也易于机器解析和生成。
JSON与XML的对比(引用自:sanpintian的CSDN博客):
1、可读性:JSON和XML的可读性可谓不相上下,一边是建议的语法,一边是规范的标签形式,很难分出胜负。
2、可扩展性:XML天生有很好的扩展性,JSON当然也有,没有什么是XML能扩展,JSON不能的。
3、编码难度:XML有丰富的编码工具,比如Dom4j、JDom等,JSON也有json.org提供的工具,但是JSON的编码明显比XML容易许多,即使不借助工具也能写出JSON的代码,可是要写好XML就不太容易了。
4、解码难度:XML的解析得考虑子节点父节点,让人头昏眼花,而JSON的解析难度几乎为0。这一点XML输的真是没话说。
5、流行度:XML已经被业界广泛的使用,而JSON才刚刚开始,但是在Ajax这个特定的领域,未来的发展一定是XML让位于JSON。到时Ajax应该变成Ajaj(Asynchronous Javascript and JSON)了。
二、导包
使用JSON需要导入以下包:
commons-beanutils.jar
commons-logging.jar
commons-lang.jar
commons-collection.jar
ezmorph.jar
json-lib.jar
三、实现
Book类的实现:
1 public class Book { 2 private String name; 3 private double price; 4 5 public String getName() { 6 return name; 7 } 8 9 public void setName(String name) { 10 this.name = name; 11 } 12 13 public double getPrice() { 14 return price; 15 } 16 17 public void setPrice(double price) { 18 this.price = price; 19 } 20 21 @Override 22 public String toString() { 23 return name+" "+price; 24 } 25 } |
1 /** 2 * @author ZWQ 3 * **/ 4 public class JsonTest { 5 public static void main(String[] args) { 6 //*********************************************************************** 7 // json基本测试 8 { 9 //新建一个JSON数组 10 JSONArray jsonArray = new JSONArray(); 11 //新建一个JSON对象 12 JSONObject json1 = new JSONObject(); 13 json1.put("id", "1"); 14 json1.put("name", "张三"); 15 json1.put("password", "123456"); 16 //将JSON对象添加到JSON数组中去 17 jsonArray.add(json1); 18 19 JSONObject json2 = new JSONObject(); 20 json2.put("id", "2"); 21 json2.put("name", "李四"); 22 json2.put("password", "654321"); 23 jsonArray.add(json2); 24 System.out.println("json数组基本测试:" + jsonArray); 25 26 //结果: 27 //[{"id":"1","name":"张三","password":"123456"},{"id":"2","name":"李四","password":"654321"}] 28 } 29 30 //*********************************************************************** 31 //将对象转成JSON字符串 32 { 33 Book book = new Book(); 34 book.setName("Java入门教程"); 35 book.setPrice(52.3); 36 //将Java对象转成JSON对象 37 JSONObject jsonObject = JSONObject.fromObject(book); 38 System.out.println("从Object到JSONObject:" + jsonObject.toString()); 39 40 //结果: 41 //从Object到JSONObject:{"name":"Java入门教程","price":52.3} 42 } 43 44 //*********************************************************************** 45 //将对象集合转成JSON字符串 46 { 47 List<Book> list = new ArrayList<Book>(); 48 Book book1 = new Book(); 49 book1.setName("高等数学I"); 50 book1.setPrice(34.1); 51 Book book2 = new Book(); 52 book2.setName("线性代数"); 53 book2.setPrice(12.7); 54 list.add(book1); 55 list.add(book2); 56 //将List集合转为JSON数组 57 JSONArray jsonArray= JSONArray.fromObject(list); 58 System.out.println("从Object集合到JSONArray:" + jsonArray.toString()); 59 60 //结果: 61 //从Object集合到JSONArray:[{"name":"高等数学I","price":34.1},{"name":"线性代数","price":12.7}] 62 } 63 64 //*********************************************************************** 65 // 将JSON字符串转为Java对象 66 { 67 String jsonString = "{name:'数据结构',price:52.3}"; 68 JSONObject jsonObject = JSONObject.fromObject(jsonString); 69 //将JSON对象转为Java对象 70 Book book = (Book) JSONObject.toBean(jsonObject, Book.class); 71 System.out.println(book.toString()); 72 73 //结果: 74 //数据结构 52.3 75 } 76 77 //*********************************************************************** 78 //将JSON字符串转为Java对象数组 79 { 80 // (2).Bean的数组 81 String jsonsString = "[{name:'数据库基础',price:52.3},{name:'Oracle 11g精华',price:42.3}]"; 82 JSONArray jsonArray = JSONArray.fromObject(jsonsString); 83 //将JSON数组转为Java对象数组 84 Book[] books = (Book[]) JSONArray.toArray(jsonArray, Book.class); 85 for (Book b : books) { 86 System.out.println(b.toString()); 87 } 88 89 //结果: 90 //数据库基础 52.3 91 //Oracle 11g精华 42.3 92 } 93 } 94 } |
四、前端解析
1 //Jquery提供的获取json的方法 2 //使用前先导入Jquery 3 4 $('#button').click(function(){ 5 //url:请求的地址 6 $.getJSON('url', { 7 //id是需要传的参数 8 id: 1 9 }, function(data) {//成功后data即为获取的json字符串 10 //例如data:[{"name":"高等数学I","price":34.1},{"name":"线性代数","price":12.7}] 11 alert("第二本书是:"+data[1].name+" 价格是:"+data[1].price); 12 }); 13 }); |
TestLink作为开源
测试管理工具,可以进行测试工程、测试计划以及执行计划的管理,而且TestLink团队提供了XML-PRC的接口供第三方工具调用,接口支持程度也比较好。
Fitnesse作为开源验收测试框架,本身可以做到测试集、
测试用例的执行,有较为优秀的测试执行行为的管理以及测试结果的收集。
由于Testlink大部分场合下是用于手工测试用例的管理,为了能够是Testlink对于测试用例管理的优点也用于Fitnesse上
自动化测试用例的管理,也为了能够让手工测试用例和自动化回归测试用例mapping起来,方便测试管理者能够清晰知道自动化测试用例在测试项目中的比例,也为了测试管理者可以较好的管理回归测试流程,考虑将Fitnesse和Testlink进行集成。
两个平台集成的基本思路是: 1. 将Testlink上的用例和Fitnesse上的用例一一mapping. 2. 将Fitnesse上用例的执行结果能够实时反馈给Testlink上用例的执行结果。
Testlink Java api client提供了一个非常好的接口,
reportTestCaseResult(projectName,testPlanName,testCaseNameOrVisiableID,buildName,execNotes,testResultStatus)
该接口有6个参数,其中
projectName: Testlink上对应的测试工程名称
testPlanName:Testlink上测试工程对应的测试计划
testCaseNameOrVisiableID: Testlink上测试用例的名称或ID,这里的ID是指测试项目前缀加上'-'在加上阿拉伯数字
buildName:Testlink上对应测试计划的构建执行计划
execNotes:是指每个case执行后的备注,可以为null
testResultStatus:是指测试用例执行结果,'p'或者'f'
通过调用给接口,我们可以完成测试用例执行结果的传递。
接下去我们要解析Fitnesse执行结果的分析:
在这里我通过一个代理proxy来完成该任务,该代理需要完成Fitnesse测试执行结果的解析,测试用例ID的解析,然后完成TestLink接口的调用
如下图所示总体架构: