操作系统约定,文件或目录的路径名由斜线(/)或反斜线(\)分割,此外,相对路径中可以采用'.'表示当前路径,'..'表示当前路径的父路径,即上一级目录。
Java编程时,需要注意,'\'后面表示的是转义字符,因此需要写两个'\'。
绝对路径:就是从根目录为参考点的文件或文件夹(即目录)所在的路径,只存在一个,具有唯一性。
比如:ipconfig.exe所在的绝对路径就是(系统盘为C:\):C:\Windows\System32\ipconfig.exe。
如代码:
import java.io.*; File file=newFile("c:\\"); //绝对路径,根目录C,下同 File file=nw File("c:"); File file=new File("c:/"); |
相对路径:就是以当前路径为参考点,所推出目的文件或目录所在的路径,没有唯一性。
比如:设当前路径为C:\Windows。以上绝对路径就可以写成 .\System32\ipconfig.exe。其中'.'表示当前路径,也可以不用写,直接写成System32\ipconfig.exe。
如代码:
import java.io.*; File file=newFile("."); //当前目录 File file=new File(".."); //当前目录的上一级目录 File file=new File(""); //所在的根目录 |
qt4如果要支持sqlite3数据库,则必须修改qmke -project和qmake之后生成的Makefile文件中的INCPATH和LIBS目录:
INCPATH问Qt支持的头文件路径,LIBS为Qt支持的库文件的路径,针对sqlite3分别为sqlite3.h和libsqlite3.so.0.8.6(注意此文件是libsqlite3.so.0这儿符号链接文件所连接到的真实文件)
1 INCPATH = -I/sqlite3.h文件的绝对路径的上一级目录(-I为大写的i)
例如我的sqlite3.h的绝对路径为:/home/linux/uboot_compile/gcc-3.4.5-glibc-2.3.6/arm-linux/arm-linux/include/sqlite3.h
则INCPATH = 后面添加 -I/home/linux/uboot_compile/gcc-3.4.5-glibc-2.3.6/arm-linux/arm-linux/include
2 LIBS = -L/(libsqlite3.so.0这个符号链接文件的绝对路径的上一级目录) -lsqlite3.so.0(-l为小写的L)
例如我的libsqlite3.so.0动态库文件路径为:/usr/lib/i386-linux-gnu/libsqlite3.so.0
则LIBS = 后面添加 -L/usr/lib/i386-linux-gnu -lsqlite3(去掉libsqlite3.so.0的Lib和后缀,然后前面加'"l")
注意:如果还是提示链接不到-lsqlite3,则做如下修改:
把Qt工程下的.pro文件打开,添加:LIBS += /usr/lib/i386-linux-gnu/libsqlite3.so.0.8.6(指定到动态库真实文件)
3 保存退出Makefile,执行make,此时你会发现makefile中的LIBS自动添加上了 /usr/lib/i386-linux-gnu/libsqlite3.so.0.8.6
需要注意的是如果重新qmake,则Makefile需要再次修改!!!
SQL注入攻击测试用例 | 说明 |
Night Night’ and 1=1# Night’ and 1=2# | 判断注入点。第一次是正常请求,如果存在注入漏洞,那么第二次请求得到结果应该与第一次一样,并且第三次请求得到的结果应该与前两次不同 |
Night’ or 1=1# | 返回所有数据,常用于有搜索功能的页面 |
Night’ union select version()# | 返回数据库版本信息 |
Night’ union select database()# | 返回当前的库名 |
Night’ union select user()# | 返回数据库的用户名信息 |
Night’ union select session_user()# |
Night’ union select system_user()# |
Night’ union select load_file(‘/etc/passwd’)# | 读取系统文件 |
Night’ select user ,password from mysql.user# | 返回数据库用户的密码信息,密码一般以MD5的方式存放 |
apache在做
压力测试这方面还是特别方便的,apache里就直接由这样的工具而且使用方便,在这之前我们需要了解apache使用的是那种并发机制
1.查看apache使用的是那种并发模型
可以直接通过cmd进入apache的bin目录 ,使用httpd.exe -l即可
找到mpm,后面的winnt就是并发模型
2.apache的默认并发数
apache的默认并发数是150,tomcat6的并发接近200,一般情况下apache使用默认的并发模型,从上面第一点我们知道了改apache的并发模型是winnt,但是如果访问量很大那150的并发就不够了,这个并发也是可以修改的
(1)打开apache安装目录下的conf文件夹,找到里面的extra子文件夹,编辑httpd-mpm.cong
(2)在最后找到如下节点,把150改为1500
<IfModule mpm_winnt_module> ThreadsPerChild 1500 MaxRequestsPerChild 0 </IfModule> |
(3)打开httpd.conf,打开如下节点,去掉下面这句前面的分号即可,之后重启apache
Include conf/extra/httpd-mpm.conf
3.测试程序的并发
通过cmd进入apache的bin目录,测试并发的命令式ab.exe -n 请求数 -c 访问的线程数(人数/并发数),如下所示
下面就是重点了
Requests per second表示服务器的吞吐量
第一个Time per request表示用户请求的平均等待时间,第二个Time per request表示服务器的平均处理时间
Failed requests表示失败的请求
这个工具用起来感觉还不错,后面还要一块OB缓存的知识,我看到网上有篇文章写得还行,我这里就不总结了
(3)打开httpd.conf,打开如下节点,去掉下面这句前面的分号即可,之后重启apache
Include conf/extra/httpd-mpm.conf
3.测试程序的并发
通过cmd进入apache的bin目录,测试并发的命令式ab.exe -n 请求数 -c 访问的线程数(人数/并发数),如下所示
下面就是重点了
Requests per second表示服务器的吞吐量
第一个Time per request表示用户请求的平均等待时间,第二个Time per request表示服务器的平均处理时间
Failed requests表示失败的请求
这个工具用起来感觉还不错,后面还要一块OB缓存的知识,我看到网上有篇文章写得还行,我这里就不总结了
就在Selenium1.0处于开发阶段的同时,另一款浏览器自动化框架WebDriver也正在ThoughtWorks公司的酝酿之中。WebDriver项目的初衷是把端对端
测试与底层测试工具隔离开。通常情况下,这种隔离手段通过适配器(Adapter)模式完成。WebDriver正是来源于该方法在许多项目上的不断实践应用,最初是HtmlUnit的封装,工具发布后很快开始支持Internet Explorer和Firefox。WebDriver的最初代码在2007年初发布。
在WebDriver最初发布时,与
Selenium RC存在显著差异,尽管它们都属于浏览器自动化的API工具。对于用户来说,最明显的区别在于Selenium RC提供基于字典的API,所有方法都在一个类中开放,而WebDriver的API更面向对象。此外,WebDriver仅支持Java,而Selenium RC提供广泛的语言支持。技术差异也很明显:Selenium Core(RC的基础)基本上是JavaScript应用,运行在浏览器的安全沙箱之内。WebDriver则尝试原生绑定到浏览器中,绕开了浏览器的安全模型,代价就是框架自身的开发投入显著增加。
在2009年8月,两个项目宣布合并,Selenium WebDriver就是合并的成果。
WebDriver的创建者Simon Stewart早在2009年8月的一份邮件中解释了项目合并的原因:
为何把两个项目合并?部分原因是WebDriver解决了Selenium存在的缺点(比如,能够绕过JS沙箱。我们有出色的API),部分原因是Selenium解决了WebDriver存在的问题(例如支持广泛的浏览器),部分原因是因为Selenium的主要贡献者和我都觉得合并项目是为用户提供最优秀框架的最佳途径。
目前,WebDriver支持的语言绑定包括Java、C#、
Python和
Ruby。它支持Chrome、Firefox、Opera和
移动端
Android、iPhone浏览器。此外,还有其他关联项目,不在同一源代码库中维护,但是和主项目(Selenium WebDriver)紧密合作,例如提供Perl绑定支持、BlackBerry浏览器支持,以及“无头”WebKit——用于持续集成的测试其无法正常显示的情况。最初的Selenium RC机制仍然维持,帮助WebDriver在浏览器不受支持的情况下提供支持。
在两个项目合并中出现了哪些架构方面的问题?学到了哪些经验和教训?Simon Stewart在《The Architecture of Open Source Applications》一文中做了详细的描述,本文参考了以下内容:
http://www.aosabook.org/en/selenium.html
http://www.infoq.com/cn/news/2011/07/selenium-arch-2
处理复杂性
软件是模块构造起来的。这些模块很复杂,作为API的设计人员们,可以选择如何处理这种复杂性。极端情况下,可能会传播这种复杂性,这意味着API的每一位用户都需要牵涉其中。另一个极端情况是承担尽可能多的复杂性并将其隔离在某个地方。这个地方对于许多想一探究竟的API用户来说黑暗而恐怖。折中方案则是API的用户,如果无须深入了解实现细节,那么只需面对当前所遇到的复杂性即可。
就在Selenium1.0处于开发阶段的同时,另一款浏览器自动化框架WebDriver也正在ThoughtWorks公司的酝酿之中。WebDriver项目的初衷是把端对端
测试与底层测试工具隔离开。通常情况下,这种隔离手段通过适配器(Adapter)模式完成。WebDriver正是来源于该方法在许多项目上的不断实践应用,最初是HtmlUnit的封装,工具发布后很快开始支持Internet Explorer和Firefox。WebDriver的最初代码在2007年初发布。
在WebDriver最初发布时,与
Selenium RC存在显著差异,尽管它们都属于浏览器自动化的API工具。对于用户来说,最明显的区别在于Selenium RC提供基于字典的API,所有方法都在一个类中开放,而WebDriver的API更面向对象。此外,WebDriver仅支持Java,而Selenium RC提供广泛的语言支持。技术差异也很明显:Selenium Core(RC的基础)基本上是JavaScript应用,运行在浏览器的安全沙箱之内。WebDriver则尝试原生绑定到浏览器中,绕开了浏览器的安全模型,代价就是框架自身的开发投入显著增加。
在2009年8月,两个项目宣布合并,Selenium WebDriver就是合并的成果。
WebDriver的创建者Simon Stewart早在2009年8月的一份邮件中解释了项目合并的原因:
为何把两个项目合并?部分原因是WebDriver解决了Selenium存在的缺点(比如,能够绕过JS沙箱。我们有出色的API),部分原因是Selenium解决了WebDriver存在的问题(例如支持广泛的浏览器),部分原因是因为Selenium的主要贡献者和我都觉得合并项目是为用户提供最优秀框架的最佳途径。
目前,WebDriver支持的语言绑定包括Java、C#、
Python和
Ruby。它支持Chrome、Firefox、Opera和
移动端
Android、iPhone浏览器。此外,还有其他关联项目,不在同一源代码库中维护,但是和主项目(Selenium WebDriver)紧密合作,例如提供Perl绑定支持、BlackBerry浏览器支持,以及“无头”WebKit——用于持续集成的测试其无法正常显示的情况。最初的Selenium RC机制仍然维持,帮助WebDriver在浏览器不受支持的情况下提供支持。
在两个项目合并中出现了哪些架构方面的问题?学到了哪些经验和教训?Simon Stewart在《The Architecture of Open Source Applications》一文中做了详细的描述,本文参考了以下内容:
http://www.aosabook.org/en/selenium.html
http://www.infoq.com/cn/news/2011/07/selenium-arch-2
处理复杂性
软件是模块构造起来的。这些模块很复杂,作为API的设计人员们,可以选择如何处理这种复杂性。极端情况下,可能会传播这种复杂性,这意味着API的每一位用户都需要牵涉其中。另一个极端情况是承担尽可能多的复杂性并将其隔离在某个地方。这个地方对于许多想一探究竟的API用户来说黑暗而恐怖。折中方案则是API的用户,如果无须深入了解实现细节,那么只需面对当前所遇到的复杂性即可。
产品交付实施一直是很多公司头痛的问题,实施问题多,实施成本高。 同样客户觉得实施团队技术薄弱不能解决客户问题,问题集解决速度慢周期长等等。那么建立一个优秀的实施团队就变得非常的关键。
组建实施团队首先要考虑实施明确几个方面的问题:
1、实施团队的具体责任是什么?
2、实施团队的人员构成是怎么样的?
3、实施团队如何与研发团队接口怎么做?
5、如何保证实施团队的工作活力?
下面我们就对每个问题进行分析:
1、实施团队的具体责任是什么?
实施团队是产品实施过程中的冲锋队,承担着在客户环境中部署产品,帮助客户上线调制,并对客户需求和问题进行解决。
2、实施团队的人员构成是怎么样的?
这是一个非常重要的问题,现在业内实施团队人员的组成大概来自于:直接招的实施人员、
测试转岗的实施人员、开发转岗的实施人员。
直招过来的实施人员是来自社会并不是企业内部,这部分可能有一定的实施经验,但是对产品和针对的客户并不了解,经过简单的培训就进入客户现场。那么问题也就来了,快速培训出来的人对产品的了解只能浮于表面,遇到问题就要求助后面的开发团队,独立解决问题能力很低。
测试转岗的实施人员是来自企业内部,他们参与了产品的研发过程,了解产品的架构和技术特点、同时他们也了解客户、熟悉客户业务、理解客户需求,这部分人员在实施过程中能够独立的接客户的业务需求问题和技术问题(当然是不触及核心技术架构的基础上)
开发转岗的实施人员同样是来自企业内部,他们参与产品的设计和开发,非常清楚产品的技术实现方法,同样比较了解客户的需求和业务,能够在现场直接解决客户的技术要求和产品在客户现场出现的bug。
那么组建实施团队的人员构造怎样的结构最优? 根据以往的经验实施团队中外来实施、测试实施、开发实施比率为1:3:1 比率比较合适。
3、实施团队如何与研发团队接口怎么做?
以前在一个外企工作时有这么一种情况,在产品在客户现场开始实施时,公司按照老外指定的实施流程来做,问题解决速度太慢,结果客户反馈非常不好。他们的流程是这样的: 实施人员在现场遇到解决不了的问题-》反馈给研发团队-》研发团队内部解决后-》交给测试进行测试-》测试通过后提交现场实施。 更严重的问题是研发团队在国外,一个问题走下来要几天时间。 客户当然不满意。
举另外一个电信行业的实施案例:在产品开始在客户实施开始前,安排开发和测试人员协助实施人员做实施前期准备(调研需求,模拟构建生产环境,现场验证,实施人员培训),正式实施开始时又有一批开发人员和测试人员进场在短期内协助实施团队实施产品上线,产品上线后所有开发人员撤离现场和留少数测试人员在现场帮助实施团队维护环境,最后测试人员全部撤离现场。 这样的实施方法前期准备时间比较长,实施成功率高。
比较合理的实施和研发接口方式就是:在实施前和实施初始阶段 研发测试和少数开发参与进来,现场实施团队成熟后撤离,产品移交成功。研发对实施应该是“ 扶上马送一程”。
4、实施团队工作流程和规范是什么样的?
产品实施要有严格实施流程和规范,避免职责不清、流程混乱、无监管的情况发生。
5、如何保证实施团队的工作活力?
实施团队人员流动比较大,这是个问题,尤其长期在客户现场实施,缺少归属感。 在实施团体里体现公司文化,让实施团队参与公司活动,实施团队人员与研发人员进行轮岗,这些都是保持实施团队工作活力的方式。 尤其对轮岗这个机制真的可以借鉴
阿里巴巴的轮岗制度,一个人在同一个岗位坐久了自然产生匹配感和枯燥感,尤其在实施团队中,那么轮岗可能是一个很好的办法,让实施人员进入研发团队参与研发工作,对个人来说是进入大学在深造了一下,对团队来说是他带来了客户需求,能够帮助研发团队更好的把控客户需求,提高产品质量,这不就是个双赢吗?
很多人都将<数据库设计范式>作为
数据库表结构设计“圣经”,认为只要按照这个范式需求设计,就能让设计出来的表结构足够优化,既能保证性能优异同时还能满足扩展性要求。殊不知,在N年前被奉为“圣经”的数据库设计3范式早就已经不完全适用了。这里我整理了一些比较常见的数据库表结构设计方面的优化技巧,希望对大家有用。
这是
MySQL数据库性能优化专题 系列的第二篇
文章:MySQL 数据库性能优化之表结构优化
系列的第一篇文章:MySQL 数据库性能优化之缓存参数优化
由于MySQL数据库是基于行(Row)存储的数据库,而数据库操作 IO 的时候是以 page(block)的方式,也就是说,如果我们每条记录所占用的空间量减小,就会使每个page中可存放的数据行数增大,那么每次 IO 可访问的行数也就增多了。反过来说,处理相同行数的数据,需要访问的 page 就会减少,也就是 IO 操作次数降低,直接提升性能。此外,由于我们的内存是有限的,增加每个page中存放的数据行数,就等于增加每个内存块的缓存数据量,同时还会提升内存换中数据命中的几率,也就是缓存命中率。
数据类型选择
数据库操作中最为耗时的操作就是 IO 处理,大部分数据库操作 90% 以上的时间都花在了 IO 读写上面。所以尽可能减少 IO 读写量,可以在很大程度上提高数据库操作的性能。
我们无法改变数据库中需要存储的数据,但是我们可以在这些数据的存储方式方面花一些心思。下面的这些关于字段类型的优化建议主要适用于记录条数较多,数据量较大的场景,因为精细化的数据类型设置可能带来维护成本的提高,过度优化也可能会带来其他的问题:
1.数字类型:非万不得已不要使用DOUBLE,不仅仅只是存储长度的问题,同时还会存在精确性的问题。同样,固定精度的小数,也不建议使用DECIMAL,建议乘以固定倍数转换成整数存储,可以大大节省存储空间,且不会带来任何附加维护成本。对于整数的存储,在数据量较大的情况下,建议区分开 TINYINT / INT / BIGINT 的选择,因为三者所占用的存储空间也有很大的差别,能确定不会使用负数的字段,建议添加unsigned定义。当然,如果数据量较小的数据库,也可以不用严格区分三个整数类型。
2.字符类型:非万不得已不要使用 TEXT 数据类型,其处理方式决定了他的性能要低于char或者是varchar类型的处理。定长字段,建议使用 CHAR 类型,不定长字段尽量使用 VARCHAR,且仅仅设定适当的最大长度,而不是非常随意的给一个很大的最大长度限定,因为不同的长度范围,MySQL也会有不一样的存储处理。
3.时间类型:尽量使用TIMESTAMP类型,因为其存储空间只需要 DATETIME 类型的一半。对于只需要精确到某一天的数据类型,建议使用DATE类型,因为他的存储空间只需要3个字节,比TIMESTAMP还少。不建议通过INT类型类存储一个
unix timestamp 的值,因为这太不直观,会给维护带来不必要的麻烦,同时还不会带来任何好处。
4.ENUM & SET:对于状态字段,可以尝试使用 ENUM 来存放,因为可以极大的降低存储空间,而且即使需要增加新的类型,只要增加于末尾,修改结构也不需要重建表数据。如果是存放可预先定义的属性数据呢?可以尝试使用SET类型,即使存在多种属性,同样可以游刃有余,同时还可以节省不小的存储空间。
5.LOB类型:强烈反对在数据库中存放 LOB 类型数据,虽然数据库提供了这样的功能,但这不是他所擅长的,我们更应该让合适的工具做他擅长的事情,才能将其发挥到极致。在数据库中存储 LOB 数据就像让一个多年前在学校学过一点Java的营销专业人员来写 Java 代码一样。
字符编码
字符集直接决定了数据在MySQL中的存储编码方式,由于同样的内容使用不同字符集表示所占用的空间大小会有较大的差异,所以通过使用合适的字符集,可以帮助我们尽可能减少数据量,进而减少IO操作次数。
1.纯拉丁字符能表示的内容,没必要选择 latin1 之外的其他字符编码,因为这会节省大量的存储空间。
2.如果我们可以确定不需要存放多种语言,就没必要非得使用UTF8或者其他UNICODE字符类型,这回造成大量的存储空间浪费。
3.MySQL的数据类型可以精确到字段,所以当我们需要大型数据库中存放多字节数据的时候,可以通过对不同表不同字段使用不同的数据类型来较大程度减小数据存储量,进而降低 IO 操作次数并提高缓存命中率。
适当拆分
有些时候,我们可能会希望将一个完整的对象对应于一张数据库表,这对于应用程序开发来说是很有好的,但是有些时候可能会在性能上带来较大的问题。
当我们的表中存在类似于 TEXT 或者是很大的 VARCHAR类型的大字段的时候,如果我们大部分访问这张表的时候都不需要这个字段,我们就该义无反顾的将其拆分到另外的独立表中,以减少常用数据所占用的存储空间。这样做的一个明显好处就是每个数据块中可以存储的数据条数可以大大增加,既减少物理 IO 次数,也能大大提高内存中的缓存命中率。
上面几点的优化都是为了减少每条记录的存储空间大小,让每个数据库中能够存储更多的记录条数,以达到减少 IO 操作次数,提高缓存命中率。下面这个优化建议可能很多开发人员都会觉得不太理解,因为这是典型的反范式设计,而且也和上面的几点优化建议的目标相违背。
适度冗余
为什么我们要冗余?这不是增加了每条数据的大小,减少了每个数据块可存放记录条数吗?
确实,这样做是会增大每条记录的大小,降低每条记录中可存放数据的条数,但是在有些场景下我们仍然还是不得不这样做:
1.被频繁引用且只能通过 Join 2张(或者更多)大表的方式才能得到的独立小字段。
2.这样的场景由于每次Join仅仅只是为了取得某个小字段的值,Join到的记录又大,会造成大量不必要的 IO,完全可以通过空间换取时间的方式来优化。不过,冗余的同时需要确保数据的一致性不会遭到破坏,确保更新的同时冗余字段也被更新。
尽量使用 NOT NULL
NULL 类型比较特殊,SQL 难优化。虽然 MySQL NULL类型和 Oracle 的NULL 有差异,会进入索引中,但如果是一个组合索引,那么这个NULL 类型的字段会极大影响整个索引的效率。此外,NULL 在索引中的处理也是特殊的,也会占用额外的存放空间。
很多人觉得 NULL 会节省一些空间,所以尽量让NULL来达到节省IO的目的,但是大部分时候这会适得其反,虽然空间上可能确实有一定节省,倒是带来了很多其他的优化问题,不但没有将IO量省下来,反而加大了SQL的IO量。所以尽量确保 DEFAULT 值不是 NULL,也是一个很好的表结构设计优化习惯。
含有abstract修饰符的class 即为抽象类,abstract类不能创建实例对象,含有abstract的方法的类必须定义为abstract class ,abstract class 里的方法不必是抽象的,抽象类中定义抽象方法必须放在具体子类中实现,所以呀,不能有抽象的构造方法或抽象的静态方法,如果子类没有实现抽象父类中的所有 方法,那么,子类也必须定义为抽象类。
接口(interface)可以说成是抽象类的特例。接口中的所有方法都必须是抽象的,接口中的方法定义默认为public abstract 。接口中的变量是全局常量,即public static final修饰的。 看一下他们在语法上的区别吧!
1,抽象类里可以有构造方法,而接口内不能有构造方法。
2,抽象类中可以有普通成员变量,而接口中不能有普通成员变量。
3,抽象类中可以包含非抽象的普通方法,而接口中所有的方法必须是抽象的,不能有非抽象的普通方法。
4,抽象类中的抽象方法的访问类型可以是public ,protected和默认类型,但接口中的抽象方法只能是public类型的,并且默认即为public abstract类型。
5,抽象类中可以包含静态方法,接口内不能包含静态方法。
6,抽象类和接口中都可以包含静态成员变量,抽象类中的静态成员变量的访问类型可以任意,但接口中定义的变量只能是public static类型,并且默认为public static类型。
7,一个类可以实现多个接口,但只能继承一个抽象类。再补充点两者在应用上的区别: 接口更多的是在系统框架设计方法发挥作用,主要定义模块之间的通信,而抽象类在代码实现方面发挥作用,可以实现代码的重用
摘要: 网站到结束阶段,发现每改一个bug,都要重新打开每个页面测试页面能否打开,并且打开页面后进行一些操作测试能否正常进行。每次部署后,发现新Bug修复后,都要做一遍功能测试。 先普及一下什么是功能测试吧。简单的说功能测试主要是参照用户手册,看看能不能完成所预先设计的功能状态,有点类似于从用户使用的角度来做测试。比如一个网站登陆的功能,做功能测试,我们需要验证能否打开登陆的页面,输入用户名,密码,看是...
阅读全文
性能测试中有一个很重要的环节,那便是设计良好的负载。对于许多
互联网企业,都采用缓存架构,那么对于这类型的测试,或者说运行时间越久,性能越好的应用,该如何模拟真实的负载呢?
或者换个方式,您在性能测试中,如何去模拟真实的负载,非思考时间类的。
精选回答
性能测试模拟真实负载是比较困难的。性能测试与真实环境的对比,通常有这样一些点:
1.客户端展现。如果是Web应用,客户端使用浏览器展现的,则一些的
压力测试工具都不具备展现的功能,也就是说,只是模拟发送http请求到接收请求,而浏览器对html内容进行渲染的时间,是无法模拟的,这很可能是真实环境体验现测试结果不相同的地方。客户端展现要与真实环境相同,必须单独进行前端性能的分析。
2.网络速率。性能测试时通常在局域网环境中,而真实的网络用户来自于全国甚至世界各地,其网络情况不一致,而且有很大的偶然性。除了对压测工具所在的机器进行一些网络限速之外,很难完全模拟到真实的网络负载情况。
3.软硬件配置。软件配置比较容易做到与真实环境一致,但硬件配置通常比较难做到。像线上使用的一些负载均衡机器或者路由设备比较昂贵,不可能在测试环境采用完全一样的拓扑和集群,当然这些对测试结果影响通常可以分析到,不会有很大偏差,但这是一个无法完全与线上保持相同的点。
4.数据分布。数据分布要做到与线上一致有3个难点,1是对新应用而言,根本没有线上数据,因此无从模拟,只能手动造数据,所以无法跟线上一致;2是即使是老的功能,线上数据因为商业机密等原因也未必能直接拿来作为测试数据;3是用户的访问路径,这点很难与线上做到一致。
功能测试尚不能覆盖掉所有的用户操作路径,何况性能测试?
以上四点,都是问题。因此性能测试很多情况下只能作为参考,用来发现明显的性能问题。如果要做到100的准确,还是要做线上的即时监控才行。