qileilove

blog已经转移至github,大家请访问 http://qaseven.github.io/

如何调试CSS的跨浏览器样式bug

首先要做的是挑选一个好的浏览器。我的选择是Chrome,因为它拥有强大的调试工具。当我在Chrome上完成调试后,我会接着在Safari或者Firefox上调试。
  如果在这些“好的”浏览器上没有达到期望的效果,很有可能是代码本身违背了CSS规则。不要试图使用hack方法来解决在这些“好的”浏览器上出现的问题,而是应该找出问题的原因。通常我会检查以下可能的BUG出处:
  HTML代码解释 - 你是否忘记闭合一个标签? 你是否用一个inline元素包住一个block元素? 违背标准的代码可能在不同的浏览器上被解释呈现成不同的效果。
  使用CSS lint工具检查CSS代码。留意那些检查出来的Errors。多数情况下,Errors比Warnings更容易引发跨浏览器差异。
  忘记使用reset样式表,而是依靠于(不同的)浏览器默认的CSS样式。
  浏览器支持性的差异。你是否使用了高级CSS3属性或者HTML5元素?查看浏览器支持性文档从而确保所有你的受众的浏览器都被涵盖。你需要设计“功能降级”来支持老式的浏览器。比如,把阴影边框降级成边框,或者把圆角降级成方块。
  在不该有空格的地方加上了空格,margin可能因此呈现得诡异。
  使用了绝对定位,可是没有设置垂直和水平偏移。这种情况下,绝对定位的元素将被呈现在跟position:static一样的位置上。但是,如果你尝试更改它的top,right,bottom或者left值,这个元素将马上“跳”到参照于它最近的相对定位的父元素的位置。
  按照“不寻常”的方式组合了不同display方式的元素。比如,W3C标准并没有说当一个table-cell紧邻一个浮动元素时应该是怎样的layout。因此,这样写的代码并不是错误的,但可能会导致跨浏览器呈现不同效果的BUG。
  空格是否影响了layout。你应该不想让排版样式依赖于空格。
  小数点像素值会导致跨浏览器的不同效果。
  接下来正文来了
  最重要的需要记住的就是,W3C标准并没有定义错误的行为。因此,如果你没有按照规范写,那么可能会导致跨浏览器不同效果;如果你组合“奇怪的”属性(例如margin和inline element),那么也可能会导致跨浏览器不同效果bug。
  Display
  我认为书写CSS就像在选择一段旅程。你需要作出一些决定.比如你要首先选择使用不同display方式的元素:block,inline,inline-block和table。当你选择好以后,你可以使用一些具体的方法来改变其实际的显示。
  块元素应该使用margin,padding,height和width。然而line-height不适用。
  行内元素应该使用line-height,vertical align和空格符。然而margin,padding,height和width不适用。
  首先,表格有垂直和水平排列方式。其次,如果你遗漏了表格中的某元素,整个表格可能会有诡异的显示。最后,margin不适用与表格的行和列,padding不适用与表格和表格的行。
  Positioning
  如果你选择使用块级元素,接下来你需要选择position方式:
  Float - 如果你使用了float,那么这个元素就变成了块级元素,而之前作用于该元素的vertical-align和line-height属性都将失效。
  Absolute - 相对于最近的相对定位的父节点来计算偏移量。当父节点和兄弟节点改变时,绝对定位的元素并不会导致reflow。这个特性有利于制作动画效果。但是,如果使用了绝对定位和动态更改内容将可能会导致显示问题,一个典型的例子是绝对定位的圆角框。
  Static – 默认的position方式。
  Fixed - 元素位置相对于浏览器窗口。不常使用的方式。
  Relative – 通常对于该元素样式不影响。只是其下属的绝对定位的子节点将相对于该节点计算偏移。
  在这里我就不列举所有的display和position组合了。总之,有两件事情需要注意:
  对于我选择的display和position方式,其他的属性(比如margin,line-height)是不是适合?
  兄弟节点的position方式是不是契合?
  比如,float,table-cell和行内元素组合在一起是否合适?浏览器将如何解释渲染?在W3C标准里有没有定义?如果没有,那么可能就有出现跨浏览器bug的风险。当然,这样的组合并不是不可以,但你要想清楚为什么要这样做,以及做好足够的跨浏览器测试
  Internet Explorer
  当你解决了在“好的”浏览器上出现的问题后,现在应开始着手IE平台。我的建议是从你希望支持的最老版本的IE开始,因为很多老版本IE上的问题在新版本中延续出现。
  就算对于IE,你也应该尝试找出问题而不是依赖于使用hack方法。盲目使用*和_的hack方法就像在一个返回错误值的函数中加入修正量(如下),而不是找出其中的算法性错误。
  return result + 4;
  当然,有时候在IE6和IE7里面使用hack是必要的。对于IE8,通常只在需要兼容CSS3的地方使用hack。通常情况下,在IE6/7里需要使用hack的地方有:
  hasLayout问题,使用zoom:1
  相对定位导致元素消失
  3px浮动BUG
  被撑大的容器的浮动错误,可是经常被overflow:hidden碰巧的掩饰了。
  还有一些不太常见的需要使用hack的情况,比如当两个浮动元素中间有comment代码时将会触发重复内容bug。对于只在IE中出现的css问题,我的建议是仔细描述你所看见的,并在google中搜索相应的解决方法。在你找到bug原因前,不要盲目使用hack掩饰它。IE自带的调试工具很糟糕,所以可能你需要给元素增加背景色来方便你查看页面上真实的排版。
实现解决方案
  当你找到bug的原因并且知道解决方法后,你同时也应该知道如何在修改代码时不破坏已有的正常效果的代码。下面是我的建议:
  1. 依赖样式级联
  2. 使用针对特定浏览器的前缀
  3. 使用针对IE6/7的*和_
  4. 不要使用针对IE8的\9
  5. 知道什么时候该放弃针对IE的hack
  6. 不要对最新版本的Firefox,Chrome,Safari使用任何hack
  1. 依赖样式级联
  首先,在任何可能的情况下都尽量依靠样式级联。浏览器总是采取他们能够读懂的最后声明的样式。所以,你应该从针对老版本浏览器的样式开始书写,这样个浏览器就能读懂和使用它能读懂的最后的样式。例如:
  .foo{
  background-color: #ccc; /* older browsers will use this */
  background-color: rgba(0,0,0,0.2); /* browsers that understand rgba will use this */
  }
  2. 使用针对特定浏览器的前缀
  使用针对特定浏览器的前缀,尤其对于还未被广泛采用的属性适用。例如:
  .foo{
  background: #1e5799; /* Old browsers */
  background: -moz-linear-gradient(top, #1e5799 0%, #2989d8 50%, #207cca 51%, #7db9e8 100%); /* FF3.6+ */
  background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#1e5799), color-stop(50%,#2989d8), color-stop(51%,#207cca), color-stop(100%,#7db9e8)); /* Chrome,Safari4+ */
  background: -webkit-linear-gradient(top, #1e5799 0%,#2989d8 50%,#207cca 51%,#7db9e8 100%); /* Chrome10+,Safari5.1+ */
  background: -o-linear-gradient(top, #1e5799 0%,#2989d8 50%,#207cca 51%,#7db9e8 100%); /* Opera 11.10+ */
  background: -ms-linear-gradient(top, #1e5799 0%,#2989d8 50%,#207cca 51%,#7db9e8 100%); /* IE10+ */
  background: linear-gradient(top, #1e5799 0%,#2989d8 50%,#207cca 51%,#7db9e8 100%); /* W3C */
  }
  注意,这套代码里有两个针对不同版本webkit的语法。前缀代码的顺序同样应该从针对老版本浏览器开始书写(参照第一条)。
  如果有一个W3C标准定义的语法,你应该把它放在最后(例如上述代码最后一行)。这样随着浏览器开始支持这些新特性的标准语法,你的代码也能够稳健表现。
  3. 使用针对IE6/7的*和_对于旧版本IE特有的bug,使用*和_来弥补。比如:
  .clearfix {
  overflow: hidden; /* new formatting context in better browsers */
  *overflow: visible; /* protect IE7 and older from the overflow property */
  *zoom: 1; /* give IE hasLayout, a new formatting context equivalent */
  }
  所有的IE hack都针对于某版本和其之前的所有浏览器,比如:
  _ 针对IE6和更早版本
  * 针对IE7和更早版本
  \9 针对IE8和更早版本 (注意,IE9在某些CSS属性上同样对于这个hack敏感)
  所以,hack代码的顺序同样也应该从针对老版本浏览器开始书写(参照第一条)。
  4. 不要使用针对IE8的\9
  我从来不会使用\9来解决IE8里面出现的样式bug。我只会在弥补浏览器支持性上使用\9来做“降级”处理。比如我使用了box-shadow(在更先进的浏览器上正常),可是在IE8下很难看,因此我使用了\9来增加了一个新border。这种情况不能依靠样式级联(参照第一条)来处理,因为这是增加一个新样式,而不是修改一个已有的样式。
  5. 知道什么时候该放弃针对IE的hack
  不要试追求在IE中得到一模一样的效果。你是否愿意浪费额外的HTTP请求,繁杂的HTML/JS/CSS代码段为了实现在IE6-8中同样看到圆角框效果?对于我个人来说,我的答案是“不会”。
  你应该知道什么时候放弃针对某功能的hack。例如,不要使用filter去模拟CSS3里的渐变效果,那样会导致性能问题和排版bug。最简单的办法是,压根不要寄希望你的网页在所有浏览器中都表现得一模一样。对于IE 6-8的用户,最好的办法就是给他们一个简单化的用户体验(注意,是简单化而不是残缺)。
  下述糟糕的代码就是使用filter去模拟CSS3里的gradient:
  .foo {
  filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#1e5799', endColorstr='#7db9e8',GradientType=0 ); /* IE6-9 */
  }
  6. 不要对最新版本的Firefox,Chrome,Safari使用任何hack
  对于Firefox,Chrome,Safari上的样式bug,最好的办法是仔细检查,很有可能这是因为你的代码违背了CSS的规则。

posted @ 2014-09-17 09:46 顺其自然EVO 阅读(323) | 评论 (0)编辑 收藏

XAMPP和Bugfree详细教程

 一、XAMPP安装配置
  xampp是一款跨平台的集成 apache + mysql + php环境,是的配置AMP服务器变得简单轻松,支持windows,solaris,
  下载地址:http://sourceforge.net/projects/xampp/files/
  启动apache和mysql服务,如果apache不能成功启动,最大原因是80端口被占用(),把占用端口的进程关掉即可.
xampp默认安装路径为:C:\xampp
  解决方案:运行在cmd中运行 (安装目录)apache/bin/httpd.exe
  如我的路径是“C:\xampp\apache\bin\httpd.exe”
  找到错误的具体原因(发现真的是端口被占用)
  “(OS 10048)通常每个套接字地址(协议/网络地址/端口)只允许使用一次。  : AH00072: mak
  e_sock: could not bind to address 0.0.0.0:80
  AH00451: no listening sockets available, shutting down
  AH00015: Unable to open logs”
  转自网络
  XAMPP修改Apache端口 无法重启服务
  由于先前装了PHPNOW,之后又装了XAMPP,XAMPP的apache服务就启动不了,改了XAMPP的apache的端口号后,服务还是无法启动;
  解决方法:由于apache中httpd.conf文件加载了SSL,而之前已有SSL,所以XAMPP要修改apache与SSL才可使用,或在httpd.conf文件中将SSL的加载用#号注释掉,操作如下:
  打开apache配置文件,如D:\xampp\apache\conf\httpd.conf:
  修改“Listen 80”为“Listen 8080”;
  修改“ServerName localhost:80”为“ServerName localhost:8080”;
  打开SSL加载文件,如D:\xampp\apache\conf\extra\httpd-ssl.conf
  将所有443端口改为4433端口 或 直接在Apache配置文件httpd.conf中,去掉或注释“Include "conf/extra/httpd-ssl.conf"”
  最后启动mYSQL发现启动不了,原因是我已经安装了dedeCMS,其中也使用了XAMPP,所以果断把安装目录删除了,重装,发现OK了,哈哈
  
  表示已经安装成功,点击界面上排右侧可切换多种语言,这里选择“中文”,将界面语言设置为中文。
  选择左边的“安全”选项
  
  红字是不安全的,所以要去掉红字。
  MySQL安全控制台&XAMPP目录保护
  浏览器中输入http://localhost/security/xamppsecurity.php ,敲回车后出现如下图:
  
  为mysql root设置密码“111111”,输入自己的密码(这里需要自己设置密码);PhpMyAdmin 认证选择http,然后点击【改变密码】,密码设置成功。
  设置Xampp目录保护,输入用户名和密码,点击【保护XAMPP文件夹】后,提示XAMPP目录保护设置成功。
  一定要记住密码哦,每次配置的时候都需要输入用户名和密码的。
  下面用PHPmyadimin配置mysql,在浏览器中输入http://localhost/phpmyadmin,敲回车后如下图
  
  下面用PHPmyadimin配置mysql,在浏览器中输入http://localhost/phpmyadmin,敲回车后如下图
  刚才设置的密码在这里要用到了,用户名输入root,密码输入刚才自己设置的密码。就可以进入数据库了。
  如果重新登录phpmyadmin,发现无法连接,需要在PHPmyadmin下配置config.inc.php文件,该文件位于
  C:\xampp\phpMyAdmin中,找到config.inc.php文件,打开编辑,配置如下:
  cfg[′Servers′][i]['auth_type']     = 'http';
  cfg[′Servers′][i]['user'] = 'root';
  cfg[′Servers′][i]['password'] = '123456';
  pwd那行,是根据自己情况设置的。保存一下就可以了。
  设置PHP运行于安装模式
  这里设置和XAMPP 1.7的版本不同,1.8的版本中设置:
  在安装好的XAMPP界面点击Apache后侧的Config会弹出一个下拉框,这里选择打开
  PHP(php.ini),文档打开后,查找safe_mode字段设置为ON保存退出。
  然后通过http://localhost/security/index.php检查其状态。
  bugfree3.0.4下载、安装和配置:
  3.1 下载地址:
  3.2 安装步骤:
  3.2.1 解压后拷贝bugfree
  3.0.4至xampp安装目录的htdocs文件夹的根目录下,例如D: \xampp\htdocs\,命名为bugfree3;
  3.2.2 浏览器中输入http://localhost/bugfree3/install/,所有环境都检查ok后 【继续】按钮变为可点击状态;
上图错误解决方法:xampp安装目录的htdocs文件夹的根目录下新建BugFile文件夹。 修改后,点击【继续】至下图
  解决:将上图的数据库用户名改为root即可
  完成安装,进入BugFree,初始用户名: root  初始密码:111111
  
  安装成功了:
  

posted @ 2014-09-17 09:42 顺其自然EVO 阅读(8381) | 评论 (1)编辑 收藏

以用户为中心的设计---可用性测试

  可用性测试是指,让一群有代表性的用户尝试对产品进行典型造作,同时观察员和开发人员在一旁观察,聆听,做记录。
  每个产品设计者都希望自己的产品可用性非常的棒,非常的适合用户使用习惯,减少用户学习成本,并且具备更多人性化的功能。这也是每个互联网公司所追求的,那么为了能在上线前,先评估产品的使用情况,我们会有一个用户研究部门组织人员进行所谓的可用性测试。
  可用性测试有几点我们需要明白:
  1.用户是谁,找几个用户
  2.如何设计任务
  3.如何进行测试
  4.如何分析找到可用性问题
  1.用户是谁,如何找用户
  在我们进行可用性测试时,我们应该是找那些用户,几个用户,一般来说多找“轻用户”和“有潜在需求的人”;如果我们资金不足的情况下,可请5名参与测试人员和5名陪同测试人员,(也不是说人员越来约好,5个人可以把产品问题的80%找到),1个主持人。装上必要的屏幕录像软件,即时的记录用户的操作轨迹。
  2.如何设计任务
  如果你实在不知道该测试那些,那么请您把产品的功能,按顺序排列到表格,找出产品核心功能,再找出核心功能5个最重要的模块,或者按照核心功能设计5个任务,任务不宜过多,如果多了测试人员烦躁,陪同人员也没不耐烦。
  3.如何进行测试
  不要听用户说,要看他操作,说的不必做的来得实在。人往往是说一套做一套的。如果用户操作出错,先不用提醒,看用户是否自行解决,陪同人员同时记录问题,但不要急于讨论问题的解决方案。马上想到的方案或者用户提出的方案都不一定是最好的。这个工作可以留待可以安静思考或者大家讨论时进行。
  4.如何分析找到可用性问题
  召集所有陪同人员,将所以记录的问题汇总,然后找出可以马上改进的问题,先把这些问题处理,接下来把大的东西再仔细的通过录像,笔记进行仔细的考虑,后续与产品,交互等一起进行改进。

posted @ 2014-09-17 09:40 顺其自然EVO 阅读(209) | 评论 (0)编辑 收藏

关于UNIX功能测试宏

 UNIX的功能测试宏,在头文件中定义了很多POSIX.1和XPG3的符号。但是除了POSIX.1和XPG3定义外,大多数实现在这些头文件中也加上了他们自己的定义。如果在编译一个程序时,希望它只是用POSIX定义而不使用任何实现定义的限制,那么就需要定义常数_POSIX_SOURCE,所有POSIX.1头文件中都是用此常数。当该常数定义时,就能排除任何实现专有的定义。
  常数_POSIX_SOURCE及对应的常数_XOPEN_SOURCE被称为功能性测试宏(feature test macro)。所有功能测试宏都以下划线开始。要使用他们时,通常在cc命令行中以下列方式定义:
  cc -D_POSIX_SOURCE file.c
  这使得在C程序包括任何头文件之前,定义了功能测试宏。如果我们仅想用POSIX.1定义,那么也可以将源文件的第一行设置为:
  #define _POSIX_SOURCE 1
  另一个功能测试宏是:__STDC__,它由符合ANSI C标准的编译程序自动定义。这样就允许我们编写ANSI C编译程序和非ANSI C编译程序都能编译的程序。例如,一个头文件可能会是:
void *myfunc(const char*, int);
#else
void *myfunc();
#endif
#ifdef __STDC__
void *myfunc(const char*, int);
#else
void *myfunc();
#endif
  这样就能发挥ANSI C原型功能的长处,要注意在开始和结束的两个连续的下划线常常打印成一个长下划线。

posted @ 2014-09-17 09:38 顺其自然EVO 阅读(206) | 评论 (0)编辑 收藏

测试用例在Scrum中有一席之地吗?

 在Scrum中,需求通常以用户故事表达。那么在Scrum中可以使用用例吗?如果可以的话,什么情况下我们应该使用用例呢?
  Scott Kendrick问到:
  用例在Scrum中有一席之地吗?我的直觉是,如果正确编写了用户故事,那就足以驱动讨论和协作了,同时也足以用来制定测试用例了。
  首先,Scrum要求我们使用用户故事,而不要使用用例吗?Roy Morien认为不是:
  Scrum没有强制任何引发诱导和记录需求的方法,除了推荐面对面的对话、日常的站立会议(当然如果你想坐下也可以)、sprint计划会议、甚至是用户故事分析,Scrum推荐的就只有协作活动和透明性了。根据这些指导原则,我想这取决于你实际想做什么。
  鉴于此,在什么情况下你会想使用用户故事呢?Charles Bradley建议:
  通常对于新的Scrum团队,在他们转向Scrum的头几个月,我建议他们就使用他们以前的需求搜集方法。学习Scrum时,不去学习一种全新的需求搜集方法会让学习变得非常困难。
  同时Charles Bradley认为,“[……]Scrum的指导原则表明大部分Scrum团队应该使用用户故事,而对于那些要求‘任务/生命周期的行为要非常确定’的团队,可以使用用例”。Adam Sroka不同意这种方法:
  传统观点认为,“关键”的应用程序需要更多文档。我认为这是不对的。关键应用程序需要的是更多(以及更好)的验证。要做到这一点,就需要详尽的自动化测试,许多做“关键”应用程序的团队都不那么做,这点我不能理解。
  但是,在纯粹的功能范围外,用例文档可能会提供价值。Charles Bradley写到:
  嗯,我曾经在航空领域工作过一段时间,尽管我没有完备的知识来支持这份工作(比如,什么需求必须具备这个东西),在我们从事文档工作的时候,让我记忆犹新的是,编写文档的目的不是过程审计,而是找出飞机坠毁的起因和责任方(监管部门,诉讼保护)。因此,某些必要的文档有助于(保护公司)那样的工作,而且我认为,在某些时候用例可能会比用户故事更加有助于证实你的案例(避免出错)。
  像敏捷方法的所有方面一样,对于用例给组织带来的价值,应该要仔细检查。你从付出的精力中究竟得到了什么?毕竟,就像Ron Jeffreis所说的,“我还没有碰到过很多实际的人,真正善于编写用例。”如果你承认你可能不擅长编写用例,那么有什么事情是你一直在做的,能给你的组织带来更多价值?

posted @ 2014-09-17 09:32 顺其自然EVO 阅读(286) | 评论 (1)编辑 收藏

Java中的JSON对象的使用

申明:没工作之前都没听过JSON,可能是自己太菜了。可能在前台AJAX接触到JSON,这几天要求在纯java的编程中,返回JSON字符串形式。
  网上有两种解析JSON对象的jar包:JSON-lib.jar和json.jar,这里主要介绍JSON-lib.jar。
  jar包地址如下:
  json-lib-2.4-jdk15.jar所需全部JAR包.rar
  一、JSON-lib.jar还依赖以下jar包:
  commons-lang.jar
  commons-beanutils.jar
  commons-collections.jar
  commons-logging.jar
  ezmorph.jar
  json-lib-2.2.2-jdk15.jar
  二、应用
  JSON也是以key-value形式存在的。key是字符串,value可以是基本类型、JSONArray、JSONObject.
  JSONArray:[],望文生义也知道,他是数组形式,又可要放多个JSON
  JSONObject:{}就放一个JSON。
  由于他们的他们可以嵌套形式就比较多。
  三、输出JSON实例考虑到对[]、{}进行对比,区别重复的变量,对变量名进行了首字母大写,显得不规范了。
import net.sf.json.JSONArray;
import net.sf.json.JSONObject;
public class JSONTest {
public static void main(String[] args) {
JSONObject container1 = new JSONObject();
container1.put("ClassName", "高三一班");
System.out.println(container1.toString());
JSONArray className = new JSONArray();
className.add("高三一班");
container1.put("className", className);
System.out.println(container1.toString());
JSONObject classInfo = new JSONObject();
classInfo.put("stuCount", 50);
classInfo.put("leader", "rah");
container1.put("classInfo", classInfo);
System.out.println(container1);
JSONObject ClassInfo = new JSONObject();
JSONArray stuCount = new JSONArray();
stuCount.add(50);
JSONArray leader = new JSONArray();
leader.add("rah");
ClassInfo.put("stuCount", stuCount);
ClassInfo.put("leader", leader);
container1.put("ClassInfo", ClassInfo);
System.out.println(container1);
JSONArray students = new JSONArray();
JSONObject studentOne = new JSONObject();
studentOne.put("name", "张麻子");
studentOne.put("sex", "男");
studentOne.put("age", 12);
studentOne.put("hobby", "java develop");
JSONObject studentTwo = new JSONObject();
studentTwo.put("name", "王瘸子");
studentTwo.put("sex", "男");
studentTwo.put("age", 13);
studentTwo.put("hobby", "C/C++ develop");
students.add(studentOne);
students.add(studentTwo);
container1.put("students", students);
System.out.println(container1);
JSONArray Students = new JSONArray();
JSONObject StudnetOne = new JSONObject();
JSONArray name1 = new JSONArray();
name1.add("张麻子");
JSONArray sex1 = new JSONArray();
sex1.add("男");
JSONArray age1= new JSONArray();
age1.add("12");
JSONArray hobby1 = new JSONArray();
hobby1.add("java develop");
StudnetOne.put("name", name1);
StudnetOne.put("sex", sex1);
StudnetOne.put("age", age1);
StudnetOne.put("hobby", hobby1);
JSONObject StudnetTwo = new JSONObject();
JSONArray name2 = new JSONArray();
name2.add("王瘸子");
JSONArray sex2 = new JSONArray();
sex2.add("男");
JSONArray age2= new JSONArray();
age2.add("13");
JSONArray hobby2 = new JSONArray();
hobby2.add("C/C++ develop");
StudnetTwo.put("name", name2);
StudnetTwo.put("sex", sex2);
StudnetTwo.put("age", age2);
StudnetTwo.put("hobby", hobby2);
Students.add(StudnetOne);
Students.add(StudnetTwo);
container1.put("Students", Students);
System.out.println(container1);
JSONArray teachers = new JSONArray();
teachers.add(0,"王老师");
teachers.add(1,"李老师 ");
container1.put("teachers", teachers);
System.out.println(container1);
JSONArray Teachers = new JSONArray();
JSONObject teacher1 = new JSONObject();
teacher1.put("name", "小梅");
teacher1.put("introduce","他是一个好老师");
JSONObject teacher2 = new JSONObject();
teacher2.put("name", "小李");
teacher2.put("introduce","他是一个合格的老师");
Teachers.add(0,teacher1);
Teachers.add(1,teacher2);
container1.put("Teachers", Teachers);
System.out.println(container1);
}
}
运行结果:
{"ClassName":"高三一班"}
{"ClassName":"高三一班","className":["高三一班"]}
{"ClassName":"高三一班","className":["高三一班"],"classInfo":{"stuCount":50,"leader":"rah"}}
{"ClassName":"高三一班","className":["高三一班"],"classInfo":{"stuCount":50,"leader":"rah"},"ClassInfo":{"stuCount":[50],"leader":["rah"]}}
{"ClassName":"高三一班","className":["高三一班"],"classInfo":{"stuCount":50,"leader":"rah"},"ClassInfo":{"stuCount":[50],"leader":["rah"]},"students":[{"name":"张麻子","sex":"男","age":12,"hobby":"java develop"},{"name":"王瘸子","sex":"男","age":13,"hobby":"C/C++ develop"}]}
{"ClassName":"高三一班","className":["高三一班"],"classInfo":{"stuCount":50,"leader":"rah"},"ClassInfo":{"stuCount":[50],"leader":["rah"]},"students":[{"name":"张麻子","sex":"男","age":12,"hobby":"java develop"},{"name":"王瘸子","sex":"男","age":13,"hobby":"C/C++ develop"}],"Students":[{"name":["张麻子"],"sex":["男"],"age":["12"],"hobby":["java develop"]},{"name":["王瘸子"],"sex":["男"],"age":["13"],"hobby":["C/C++ develop"]}]}
{"ClassName":"高三一班","className":["高三一班"],"classInfo":{"stuCount":50,"leader":"rah"},"ClassInfo":{"stuCount":[50],"leader":["rah"]},"students":[{"name":"张麻子","sex":"男","age":12,"hobby":"java develop"},{"name":"王瘸子","sex":"男","age":13,"hobby":"C/C++ develop"}],"Students":[{"name":["张麻子"],"sex":["男"],"age":["12"],"hobby":["java develop"]},{"name":["王瘸子"],"sex":["男"],"age":["13"],"hobby":["C/C++ develop"]}],"teachers":["王老师","李老师 "]}
{"ClassName":"高三一班","className":["高三一班"],"classInfo":{"stuCount":50,"leader":"rah"},"ClassInfo":{"stuCount":[50],"leader":["rah"]},"students":[{"name":"张麻子","sex":"男","age":12,"hobby":"java develop"},{"name":"王瘸子","sex":"男","age":13,"hobby":"C/C++ develop"}],"Students":[{"name":["张麻子"],"sex":["男"],"age":["12"],"hobby":["java develop"]},{"name":["王瘸子"],"sex":["男"],"age":["13"],"hobby":["C/C++ develop"]}],"teachers":["王老师","李老师 "],"Teachers":[{"name":"小梅","introduce":"他是一个好老师"},{"name":"小李","introduce":"他是一个合格的老师"}]}
  四、遍历JSON实例
  以上面的输出的JSON字符串进行按顺序给它遍历
  String ClassName1 = (String) container1.get("ClassName");
  System.out.println("ClassName data is: " + ClassName1);
  JSONArray className1 = container1.getJSONArray("className");
  System.out.println("className data is: " + className1);
  JSONObject classInfo1 = container1.getJSONObject("classInfo");
  System.out.println("classInfo data is: " + classInfo1);
  JSONObject ClassInfo1 = container1.getJSONObject("ClassInfo");
  System.out.println("ClassInfo data is: " + ClassInfo1);
  JSONArray students1 = container1.getJSONArray("students");
  System.out.println("students data is: " + students1);
  JSONArray Students1 = container1.getJSONArray("Students");
  System.out.println("Students data is: " + Students1);
  JSONArray teachers1 = container1.getJSONArray("teachers");
  for(int i=0; i < teachers1.size(); i++){
  System.out.println("teahcer " + i + " is: "+ teachers1.get(i));
  }
  JSONArray Teachers1 = container1.getJSONArray("Teachers");
  for(int i=0; i < Teachers1.size(); i++){
  System.out.println("Teachers " + i + " is: "+ Teachers1.get(i));
  }
  遍历结果:
  ClassName data is: 高三一班
  className data is: ["高三一班"]
  classInfo data is: {"stuCount":50,"leader":"rah"}
  ClassInfo data is: {"stuCount":[50],"leader":["rah"]}
  students data is: [{"name":"张麻子","sex":"男","age":12,"hobby":"java develop"},{"name":"王瘸子","sex":"男","age":13,"hobby":"C/C++ develop"}]
  Students data is: [{"name":["张麻子"],"sex":["男"],"age":["12"],"hobby":["java develop"]},{"name":["王瘸子"],"sex":["男"],"age":["13"],"hobby":["C/C++ develop"]}]
  teahcer 0 is: 王老师
  teahcer 1 is: 李老师
  Teachers 0 is: {"name":"小梅","introduce":"他是一个好老师"}
  Teachers 1 is: {"name":"小李","introduce":"他是一个合格的老师"}
  上面包括了大部份的JSON的嵌套形式,可能有忽略的也可以参考上面的内容。

posted @ 2014-09-16 09:52 顺其自然EVO 阅读(257) | 评论 (0)编辑 收藏

IOS开发之显示微博表情

 在上一篇博客中山寨了一下新浪微博,在之后的博客中会对上一篇代码进行优化和重用,上一篇的微博请求的文字中有一些表情没做处理,比如带有表情的文字是这样的“我要[大笑],[得意]”。显示的就是请求的字符串,那么我们如何把文字在本地转换成表情呢?下面将要说一下显示表情的解决方案。
  要用到的知识:IOS开发中的资源文件.plist, 可变的属性字符串,TextView和正则表达式的使用。
  解决的整体思路:把源字符串同过正则匹配获取到每个表情的range, 再通过range获取元字符串中的表情字符串,如[哈哈], 在把[哈哈] 和我们.plist中item下的chs字段匹配,然后获取对应的图片名,获取图片后把图片转换成可变字符串的附件,然后做一个替换即可。先这么大致一说,下面会详细的讲解一下。
  1.要想在我们手机上显示网络请求的表情,首先我们本地得有相应的资源文件,在.plist文件中又我们想要的东西,其中存储的东西如下所示,整个root是一个数组,数组中的item是一个字典,字典中存放的时文字到图片名的一个映射,当然啦,图片名和我们本地资源的图片名相同。截图如下
  2.如何从.plist文件中获取数据呢?先通过bundle获取资源文件的路径,在通过文件路径创建数组,数组中存储的数据就是文件中的内容代码如下:
  //加载plist文件中的数据
  NSBundle *bundle = [NSBundle mainBundle];
  //寻找资源的路径
  NSString *path = [bundle pathForResource:@"emoticons" ofType:@"plist"];
  //获取plist中的数据
  NSArray *face = [[NSArray alloc] initWithContentsOfFile:path];
  3.生成我们的测试字符串,最后一个不是任何表情,不做替换。
  //我们要显示的字符串(模拟网路请求的字符串格式)
  NSString *str = @"我[围观]你[威武]你[嘻嘻]我[爱你]你[兔子]我[酷]你[帅]我[思考]你[钱][123456]";
  4.把上面的str转换为可变的属性字符串,因为我们要用可变的属性字符串在TextView上显示我们的表情图片,转换代码如下:
  //创建一个可变的属性字符串
  NSMutableAttributedString *attributeString = [[NSMutableAttributedString alloc] initWithString:str];
  5.进行正则匹配,获取每个表情在字符串中的范围,下面的正则表达式会匹配[/*],所以[123567]也会被匹配上,下面我们会做相应的处理
  //正则匹配要替换的文字的范围
  //正则表达式
  NSString * pattern = @"\\[[a-zA-Z0-9\\u4e00-\\u9fa5]+\\]";
  NSError *error = nil;
  NSRegularExpression * re = [NSRegularExpression regularExpressionWithPattern:pattern options:NSRegularExpressionCaseInsensitive error:&error];
  if (!re) {
  NSLog(@"%@", [error localizedDescription]);
  }
  //通过正则表达式来匹配字符串
  NSArray *resultArray = [re matchesInString:str options:0 range:NSMakeRange(0, str.length)]; 6.数据准备工作完成,下面开始遍历资源文件找到文字对应的图片,找到后把图片名存入字典中,图片在源字符串中的位置也要存入到字典中,最后把字典存入可变数组中。代码如下:
1     //用来存放字典,字典中存储的是图片和图片对应的位置
2     NSMutableArray *imageArray = [NSMutableArray arrayWithCapacity:resultArray.count];
3
4     //根据匹配范围来用图片进行相应的替换
5     for(NSTextCheckingResult *match in resultArray) {
6         //获取数组元素中得到range
7         NSRange range = [match range];
8
9         //获取原字符串中对应的值
10         NSString *subStr = [str substringWithRange:range];
11
12         for (int i = 0; i < face.count; i ++)
13         {
14             if ([face[i][@"chs"] isEqualToString:subStr])
15             {
16
17                 //face[i][@"gif"]就是我们要加载的图片
18                 //新建文字附件来存放我们的图片
19                 NSTextAttachment *textAttachment = [[NSTextAttachment alloc] init];
20
21                 //给附件添加图片
22                 textAttachment.image = [UIImage imageNamed:face[i][@"png"]];
23
24                 //把附件转换成可变字符串,用于替换掉源字符串中的表情文字
25                 NSAttributedString *imageStr = [NSAttributedString attributedStringWithAttachment:textAttachment];
26
27                 //把图片和图片对应的位置存入字典中
28                 NSMutableDictionary *imageDic = [NSMutableDictionary dictionaryWithCapacity:2];
29                 [imageDic setObject:imageStr forKey:@"image"];
30                 [imageDic setObject:[NSValue valueWithRange:range] forKey:@"range"];
31
32                 //把字典存入数组中
33                 [imageArray addObject:imageDic];
34
35             }
36         }
37     }
  7.转换完成,我们需要对attributeString进行替换,替换的时候要从后往前替换,弱从前往后替换,会造成range和图片要放的位置不匹配的问题。替换代码如下:
1     //从后往前替换
2     for (int i = imageArray.count -1; i >= 0; i--)
3     {
4         NSRange range;
5         [imageArray[i][@"range"] getValue:&range];
6         //进行替换
7         [attributeString replaceCharactersInRange:range withAttributedString:imageArray[i][@"image"]];
8
9     }
  8.把替换好的可变属性字符串赋给TextView
  1     //把替换后的值赋给我们的TextView
  2     self.myTextView.attributedText = attributeString;
  9.替换前后效果如下:

posted @ 2014-09-16 09:52 顺其自然EVO 阅读(1729) | 评论 (1)编辑 收藏

VS2013单元测试(使用VS2013自带的单元测试)

 1、打开VS3013,随便建一个解决方案,比如叫:LearnUnitTest,建一个类库项目LearnUnitTest_Bank,该项目中添加一个BankAccount类,这个类及类中的方法就是我们要测试的对象。
  2、给LearnUnitTest添加一个测试项目:在解决方案名称上右键=》添加=》新建项目=》VisualC#=》测试=》单元测试项目,项目名称叫LearnUnitTest_BankTest,将LearnUnitTest_Bank添加为LearnUnitTest_BankTest的引用项目,将测试项目LearnUnitTest_BankTest里默认生成的类重命名为BankAccountTest。
  对于BankAccountTest类,类上有注解TestClass,方法上有注解TestMethod。可以在这类文件里添加其他类和方法,供测试方法使用。
  首个测试:
  3、现在我们测试BankAccount类的Debit方法,我们预先确定此次测试要检查如下方面:
  a、如果信用余额(credit amount)比账户余额大,该方法就抛异常ArgumentOutOfRangeException
  b、如果信用余额小于0也抛异常
  c、如果a和b都满足,该方法会从账户余额里减去amount(函数参数)
  注意:由a、b、c可以看邮BankAccount类中的Debit方法最后一行应该是-=,而不是+=——当然了,这个是故意留下的bug,而不是微软的失误,就等着在这次测试中把它测出来,然后修正掉。
  在测试类里添加如下方法测试Debit方法:
// unit test code
[TestMethod]
public void Debit_WithValidAmount_UpdatesBalance()
{
// arrange
double beginningBalance = 11.99;
double debitAmount = 4.55;
double expected = 7.44;
BankAccount account = new BankAccount("Mr. Bryan Walton", beginningBalance);
// act
account.Debit(debitAmount);
// assert
double actual = account.Balance;
Assert.AreEqual(expected, actual, 0.001, "Account not debited correctly");
}
  测试方法的要求:
  必须要有TestMethod注解,返回类型为void,不能有参数。
  经过测试,我们发现了bug,把+=改为-=即可。
  使用单元测试改善代码:
  依然是测试Debit,本次测试想完成以下意图:
  a、如果credit amount(指的应该就是debit amount)比balance大,方法就抛ArgumentOutOfRangeException
  b、如果credit amount比0小,也抛ArgumentOutOfRangeException异常
  (1)创建测试方法
  首次尝试创建一个测试方法来处理上述问题:
  代码:
//unit test method
[TestMethod]
[ExpectedException(typeof(ArgumentOutOfRangeException))]
public void Debit_WhenAmountIsLessThanZero_ShouldThrowArgumentOutOfRange()
{
// arrange
double beginningBalance = 11.99;
double debitAmount = -100.00;
BankAccount account = new BankAccount("Mr. Bryan Walton", beginningBalance);
// act
account.Debit(debitAmount);
// assert is handled by ExpectedException
}
  注意这个方法:Debit_WhenAmountIsLessThanZero_ShouldThrowArgumentOutOfRange,意思是:当debit amount小于0时,本次测试应该会导致被测试的方法抛出ArgumentOutOfRange异常,否则本次测试就失败了,没有达到期望,需要修改Debit代码以达成本次测试期望——正所谓TDD开发。
  我们使用了ExpectedExceptionAttribute特性来断言期望的异常应当被抛出。除非方法抛出ArgumentOutOfRangeException异常,否则该特性就会导致测试失败(要注意本次测试的意图)。用正的和负的debitAmount运行这个测试,然后临时把被测试的方法(Debit方法)修改一下:当demit amount小于0时抛出一个ApplicatinException。捣腾完这些,发现本次测试基本没什么问题。
  为了测试debit amount 大于balance的情形,我们做下面几个操作:
  a、创建一个新的测试方法名叫    Debit_WhenAmountIsMoreThanBalance_ShouldThrowArgumentOutOfRange
  b、从上一个测试方法
  Debit_WhenAmountIsLessThanZero_ShouldThrowArgumentOutOfRange
  复制方法体到本测试方法
  c、把debitAmount设置为一个比balance大的值
  (2)运行测试方法
  用不同的debitAmount值运行Debit_WhenAmountIsMoreThanBalance_ShouldThrowArgumentOutOfRange
  和 Debit_WhenAmountIsLessThanZero_ShouldThrowArgumentOutOfRange
  然后运行三个测试,这样我们最开始设定的三个cases都被覆盖了。
 (3)继续分析
  后面两个测试方法Debit_WhenAmountIsMoreThanBalance_ShouldThrowArgumentOutOfRange
  和Debit_WhenAmountIsLessThanZero_ShouldThrowArgumentOutOfRange
  有些问题:两个测试运行的时候根据抛出的异常,你不知道是谁抛出的,靠ExpectedException特性做不到这件事。
  可以这样修改:
  在类里定义两个常量:
// class under test
public const string DebitAmountExceedsBalanceMessage = "Debit amount exceeds balance";
public const string DebitAmountLessThanZeroMessage = "Debit amount less than zero";
// method under test
// ...
if (amount > m_balance)
{
throw new ArgumentOutOfRangeException("amount", amount, DebitAmountExceedsBalanceMessage);
}
if (amount < 0)
{
throw new ArgumentOutOfRangeException("amount", amount, DebitAmountLessThanZeroMessage);
}
// ...
  (4)重构测试方法
  首先,移除ExpectedException特性。取而代之的处理是:我们捕获异常,来核实是在哪种条件下抛出的。
  修改一下Debit_WhenAmountIsMoreThanBalance_ShouldThrowArgumentOutOfRange
  方法:
[TestMethod]
public void Debit_WhenAmountIsGreaterThanBalance_ShouldThrowArgumentOutOfRange()
{
// arrange
double beginningBalance = 11.99;
double debitAmount = 20.0;
BankAccount account = new BankAccount("Mr. Bryan Walton", beginningBalance);\
// act
try
{
account.Debit(debitAmount);
}
catch (ArgumentOutOfRangeException e)
{
// assert
StringAssert.Contains(e.Message, BankAccount. DebitAmountExceedsBalanceMessage);
}
}
  (5)再次测试,再次重写,再次分析
  当我们用不的参数再次运行测试方法Debit_WhenAmountIsMoreThanBalance_ShouldThrowArgumentOutOfRange
  的时候,会遇到下面一些问题:
  1、如果我们使用一个比balance大的debitAmount运行,产生的测试结果是所期望的。
  2、如果使用了一个debitAmount运行,使得assert 断言失败了(比如在Debit方法的某一行返回了一个非期望的异常),也没什么问题,在本测试的情理之中。
  3、如果debitAmount是有效的(比0大比balance小)会发生什么呢?没有异常抛出,断言也不会失败,测试方法通过了。——这不是我们想要的,注意我们此次的测试初衷:要么断言成功,要么断言失败,如果压根进入不了断言代码,只能说明测试方法写的问题!
  为了解决这个问题,我们在测试方法的最后一行加入一个Fail断言,来处理没有异常发生的情况:没有异常发生,就说明此次测试没有达到期望!
  但是修改好再次运行,会发现如果所期望的异常被捕获了,测试总会失败。为了解决这个问题,我们在StringAssert之前加一个return。
  最终我们的Debit_WhenAmountIsMoreThanBalance_ShouldThrowArgumentOutOfRange
  方法如下:
[TestMethod]
public void Debit_WhenAmountIsGreaterThanBalance_ShouldThrowArgumentOutOfRange()
{
// arrange
double beginningBalance = 11.99;
double debitAmount = 20.0;
BankAccount account = new BankAccount("Mr. Bryan Walton", beginningBalance);\
// act
try
{
account.Debit(debitAmount);
}
catch (ArgumentOutOfRangeException e)
{
// assert
StringAssert.Contains(e.Message, BankAccount. DebitAmountExceedsBalanceMessage);
return;
}
Assert.Fail("No exception was thrown.")
}
  最终我们让测试代码变得更加强健,但更重要的是,在这个过程中,我也们也改善了被测试的代码——这才是测试的最终目的。

posted @ 2014-09-16 09:51 顺其自然EVO 阅读(1342) | 评论 (0)编辑 收藏

关于UNIX功能测试宏

UNIX的功能测试宏,在头文件中定义了很多POSIX.1和XPG3的符号。但是除了POSIX.1和XPG3定义外,大多数实现在这些头文件中也加上了他们自己的定义。如果在编译一个程序时,希望它只是用POSIX定义而不使用任何实现定义的限制,那么就需要定义常数_POSIX_SOURCE,所有POSIX.1头文件中都是用此常数。当该常数定义时,就能排除任何实现专有的定义。
  常数_POSIX_SOURCE及对应的常数_XOPEN_SOURCE被称为功能性测试宏(feature test macro)。所有功能测试宏都以下划线开始。要使用他们时,通常在cc命令行中以下列方式定义:
  cc -D_POSIX_SOURCE file.c
  这使得在C程序包括任何头文件之前,定义了功能测试宏。如果我们仅想用POSIX.1定义,那么也可以将源文件的第一行设置为:
  #define _POSIX_SOURCE 1
  另一个功能测试宏是:__STDC__,它由符合ANSI C标准的编译程序自动定义。这样就允许我们编写ANSI C编译程序和非ANSI C编译程序都能编译的程序。例如,一个头文件可能会是:
void *myfunc(const char*, int);
#else
void *myfunc();
#endif
#ifdef __STDC__
void *myfunc(const char*, int);
#else
void *myfunc();
#endif
  这样就能发挥ANSI C原型功能的长处,要注意在开始和结束的两个连续的下划线常常打印成一个长下划线。

posted @ 2014-09-16 09:51 顺其自然EVO 阅读(240) | 评论 (0)编辑 收藏

数据库中的事物处理

 数据库
  数据库的更新通常都是由客观世界的所发生的事件引起的。为保证数据库内容的一致,就要将数据库的一组操作作为一个整体来进行,要么全部成功完成,要么全部失败退出。如果由于故障或其它原因而使一组操作中有一些完成,有一些未完成,则必然会使得数据库中的数据出现不一致,从而使得数据库的完整性受到破坏。因此,更新操作序列必须作为一个整体在DBMS执行时出现,即“要么全做,要么全不做”。SQL提供了事务处理的机制,来帮助DBMS实现上述的功能。
  事务处理
  事务处理(TRANSACTION)的每个语句是由一个或多个SQL语句序列结合在一起所形成的一个逻辑处理单元。事务处理中句都是完成整个任务的一部分工作,所有的语句组织在一起能够完成某一特定的任务。DBMS在对事务处理中的语句进行处理时,是按照下面的约定来进行的,这就是“事务处理中的所有语句被作为一个原子工作单位,所有的语句既可成功地被执行,也可以没有任何一个语句被执行”。DBMS负责完成这种约定,即使在事务处理中应用程序异常退出,或者是硬件出现故障等各种意外情况下,也是如此。在任何意外情况下,DBMS都负责确保在系统恢复正常后,数据库内容决不会出现“部分事务处理中的语句被执行完”的情况。
  sql语言
  sql语言为事务处理提供了两个重要的语句,它们是COMMIT和ROLLBACK语句。它们的使用格式是:
  COMMIT WORK
  ROLLBACK WORK
  COMMIT语句用于告诉DMBS,事务处理中的语句被成功执行完成了。被成功执行完成后,数据库内容将是完整的。而ROLLBACK语句则是用于告诉DBMS,事务处理中的语句不能被成功执行。这时候,DBMS将恢复本次事务处理期间对数据库所进行的修改,使之恢复到本次事务处理之前的状态。
  事务处理:
QSqlDatabase::database().transaction();
QSqlQuery query;
query.exec("SELECT id FROM employee WHERE name = 'Torild Halvorsen'");
if (query.next())
{
int employeeId = query.value(0).toInt();
query.exec("INSERT INTO project (id, name, ownerid) "
"VALUES (201, 'Manhattan Project', "
+ QString::number(employeeId) + ")");
}
QSqlDatabase::database().commit();
  如果数据库引擎支持事务处理,则函数QSqlDriver::hasFeature(QSqlDriver::Transactions)将返回 真。
  可以通过调用QSqlDatabase::transaction()来初始化一个事务处理。之后执行你想在该事务处理的工作。
  完了再执行QSqlDatabase::commit()来提交事务处理或QSqlDatabase::rollback()取消事务处理。

posted @ 2014-09-16 09:51 顺其自然EVO 阅读(194) | 评论 (0)编辑 收藏

仅列出标题
共394页: First 上一页 46 47 48 49 50 51 52 53 54 下一页 Last 
<2024年11月>
272829303112
3456789
10111213141516
17181920212223
24252627282930
1234567

导航

统计

常用链接

留言簿(55)

随笔分类

随笔档案

文章分类

文章档案

搜索

最新评论

阅读排行榜

评论排行榜