Web 2.0 浏览器端可靠性测试第1部分(浏览器端可靠性测试的概念和背景)
Web 2.0 是一个体现当代网络技术发展趋势的流行概念。它使得基于 Web 的信息交互和用户间协作性更加灵活和丰富。很多的社交网站、博客、wiki,都是 Web 2.0 技术的典型应用。
我们知道,Web 2.0 最突出的特色就是丰富的客户端技术;而客户端技术中,最基本也最重要的技术就是 JavaScript。通过大量的 JavaScript 脚本,我们可以创建动态的页面展示,活泼的界面效果,以及与服务器之间进行数据交互等。
然而,我们往往忽略了一个重要问题,就是大量使用这些 JavaScript 脚本可能对浏览器端带来的种种问题。在很多 Web 应用的使用过程中,我们会发现页面响应越来越慢,浏览器进程占用的内存不断增多(图 1),甚至浏览器会异常关闭(图 2)。诸如此类问题,都会导致极差的用户体验。现在我们逐渐认识到了这一问题,并且提出了浏览器端可靠性测试的概念,来保证我们的 Web 应用拥有更高的可靠性和稳定性。
图 1. 用 Windows Perfmon 监控的 IE 进程内存消耗情况
图 2 . IE 异常关闭
概念
浏览器端可靠性测试,就是以浏览器为测试平台,通过模拟用户在真实场景下的页面操作(点击、拖拽),来发现 Web 应用中潜在可靠性问题的测试。测试目的是确保 Web 应用在浏览器上能达到令人满意的用户体验和可靠性。
浏览器端可靠性测试的特点
通常,浏览器端可靠性测试具有以下几个特点:
- 单用户,单浏览器进程
与服务器端可靠性测试不同,浏览器端的可靠性测试,是模拟一个用户在一个客户端(浏览器)中的操作。
- 最大限度模拟客户端的操作行为
测试中应用的场景应最大限度的模拟最终用户的操作行为,比如点击、拖拽、复制、粘贴等等,并按功能点的重要程度和用户操作的频率来设计测试场景和测试用例,以便使测试结果更接近真实结果。
- 浏览器相关
不同的浏览器会有不同的测试结果;现在用户使用的浏览器众多。为了确保用户在不同浏览器 ( 包括操作系统 ) 下都能达到高可靠性,我们需要尽可能地在产品所支持的浏览器和操作系统下进行测试。目前市场上的浏览器种类繁多,这无疑对我们的测试是一个挑战。
- 有助于发现客户端的设计缺陷
通过浏览器端可靠性测试,可以发现因为客户端设计缺陷或考虑不周而导致的问题,比如大量复杂的 JavaScript 代码可能导致用户响应时间过长。
浏览器端可靠性测试的流程
我们将浏览器端可靠性测试的测试流程分为:测试场景设计、脚本开发、环境准备、测试执行(包括压力测试和长时间测试)、发现问题、分析问题及报告缺陷、编写测试报告几个部分。
测试的流程图
图 3. 浏览器端可靠性测试的流程图
浏览器端与服务器端可靠性测试的比较
表 1. 浏览器端可靠性测试和服务器端可靠性测试的比较
浏览器端测试 | 服务器端测试 | |
---|---|---|
用户数 | 单用户 | 多用户 |
测试对象 | 浏览器端的问题,主要是 JavaScript 代码,主要发现 memory leak (内存泄漏)和响应时间问题, 与浏览器关系密切 | 测试 Server 端代码,例如 Java, C/C++ 等,与浏览器无关 |
使用工具 | RFT(Rational Functional Tester),Selenium 等 | RPT(Rational Performance Tester), LoadRunner 等 |
测试经验 | 极少测试经验,Web 2.0 以来新兴测试领域 | 已有成熟的测试经验 |
测试特点 | 衡量单客户端用户真实操作体验 | 衡量服务器端对来自多客户端的承载能力通过模拟用户的操作行为 |
测试流程说明
- 测试场景设计
浏览器端的可靠性测试中,需要设计两种类型的测试场景:压力测试和长时间测试。压力测试一般针对关键功能点和用户操作频率较高的操作。长时间测试则是对整个产品进行的可靠性把关。
- 测试脚本开发
浏览器端的可靠性测试主要是通过执行自动化脚本完成的。所以,开发健壮的脚本来模拟浏览器端的 GUI 操作,会使我们的测试事半功倍。从整个测试过程来看,自动化测试可以节约我们大量的时间和精力。
值得说明的是,我们在编写脚本的同时,需要注意几个方面的问题。首先,我们要考虑测试脚本对不同浏览器的兼容问题。尽可能通过一些公共属性查找页面元素,以使脚本能够顺利地跨浏览器执行。其次,利用日志来分析潜在的可靠性问题。我们通常将对页面的操作信息(也可能包括浏览器的内存占用等信息)打印在日志文件中,便于分析。
- 测试环境准备
准备测试环境是测试执行前最关键的一步。我们一般会制定一份检查列表,通过勾对每个检查项目来确保测试环境的正确。下面我们列出一些针对浏览器端测试,需要考虑的环境因素:
- 操作系统
- 操作系统版本及补丁要在测试前指定好,并严格按照要求进行安装。因为某些微小的差别可能会导致不同的测试结果。
- 关闭操作系统自动更新的设置,关闭桌面屏保,禁止自动关闭显示器、硬盘。以上这些都是为了避免测试脚本在运行过程中意外中止。
- 浏览器
- 浏览器版本要正确,特别注意浏览器的小版本号
- 关闭自动更新浏览器的选项,同时禁止自动更新浏览器插件
- 关闭一切不使用的、或可能对可靠性产生影响的浏览器插件。禁用插件的目的是杜绝插件本身对测试结果的干扰,比如插件本身可能带来的导致浏览器内存泄露等问题。
- 监测工具
配置监测工具,指定需要收集的数据,并在监测工具中配置相应的计数器,比如内存占用、CPU 等信息。对浏览器端可靠性测试而言,我们主要收集浏览器进程的相关信息。
- 测试数据
根据测试场景,准备必要的测试数据。用于测试的数据通常要求具有代表性。一方面是为了能够通过数据覆盖到更多的功能点,另一方面也可以最大限度地模拟用户的真实使用状况。
- 服务器端
有时,服务器端的相关配置也会对浏览器端的测试产生影响。比如测试一个基于 WebSphere Application Server 的应用。当我们需要进行一个持续 3 小时的测试的时候,我们就需要对 WAS 上的 LTPA timeout 进行必要的修改,使它大于 3 小时。否则,当测试脚本执行到 2 小时(默认值)的时候,页面会自动 logout 退出,导致脚本无法继续执行。
- 执行测试
执行测试的步骤如下图所示。主要是通过运行自动化脚本来模拟用户操作页面,同时使用监测工具监测浏览器进程的过程。
图 4. 执行测试的步骤
- 发现问题
我们常常在测试还未结束的时候就能发现问题。通过监测工具实时地监测浏览器进程,很多问题在测试过程中就已经表现出来了。
下面就是一个典型的例子:
图 5. 通过检测工具发现内存泄露
从图中可以看到,在测试持续了 21 分钟的时候,从系统监测工具中,已经清晰地看到一个内存增长趋势图。图中的内存占用由开始的 100 多兆,迅速涨到近 800M。这说明此段测试中所执行的页面操作,导致了严重的浏览器端内存泄露。
- 分析问题及报告缺陷
我们发现问题以后,一般要先做必要的分析。然后将分析结果分享给开发人员,帮助他们快速的定位和解决问题。
在报告缺陷的时候,我们通常要提供下面的信息给开发人员:
- 能够重现问题的步骤
- 测试环境:操作系统的版本、浏览器的版本
- 是否是浏览相关的问题,比如是否只有在 Internet Explorer 上才会出现的问题,而在其他浏览器是没有问题的
- 给出测试数据。比如计算出每次操作导致的内存泄漏。如果在多个浏览器上都存在内存泄漏,要在不同的浏览器上进行测试,并将内存泄漏的数据进行比较。
- 其他一些必要的信息和分析结果。比如用其他工具分析的数据,或是代码走查发现的问题等等。
- 编写测试报告
测试报告可以通过通用的模板生成的。测试报告里要求记录所有关于测试的信息。包括测试环境、测试场景、测试数据、测试步骤、测试结果、趋势图、测试分析、日志文件等等。
测试报告不仅记录了整个测试的过程,留下文档,也对我们对分析产品问题提供了大量的历史数据和经验,更有助于技术交流和分享。
测试报告模板样例:
标题
压力测试 - 验证产品页面切换时浏览器端的可靠性测试结果
通过 / 未通过概要
描述测试的任务、目的,记录测试人员和测试日期。测试环境
包括服务器端和客户端的测试环境、软件和工具等的配置信息。测试步骤
包括测试前的准备工作以及测试的执行步骤。用户定义
定义测试时长、操作时间间隔、监测取值间隔、测试数据准备等信息。测试场景
描述测试用例和操作步骤资源占用
内存使用表
记录内存使用的最大、最小、平均值等信息。趋势图
由监测工具展示的内存使用趋势图测试结果分析
根据上述测试数据分析问题所在。需要描述分析的方法和依据。日志文件
提供监测工具和测试软件在测试执行过程中收集的测试数据。缺陷报告和分析
是否有缺陷报告及分析产生的原因。
测试的方法和工具
测试方法
按照测试工具分
按照测试工具来分,测试方法分成手工测试和自动化测试两种。前面我们提到了自动化测试,然而在实际测试中,我们通常会采用手工测试与自动化测试相结合的方法。
- 手工测试
手工测试是指测试人员通过手工操作页面,同时使用监测工具来监测浏览器进程的各计数器数值的变化。在手工测试中,我们经常可以发现一些明显的可靠性问题,比如严重的内存泄漏。由于手工测试比较简单,不需要准备测试脚本,所以,对关键功能点的压力测试,我们通常先进行手工测试,在没有发现明显问题的时候再开始自动化测试。
那么怎样通过手工测试来发现问题呢?
我们在对页面进行操作的同时,使用监测工具来监测浏览器进程内存的变化。记录每次页面操作(点击或拖动)的开始和结束时刻的内存占用,重复多次,就可以得到一组数据,从而看出内存的变化趋势。需要注意的是,对于一个页面操作,我们通常会不计算第一次操作引起的内存增长,因为通常在第一次操作的时候,脚本创建一些对象,从而会导致内存的增长,这种增长属于正常现象,并不是我们常说的内存泄漏。
- 自动化测试
通过自动化测试,我们可以发现更多的问题。比如,一些细微的内存泄漏,只有在经过脚本重复几十次上百次的操作后,积累到一定的程度,才可以被发现。另外,一些响应时间等指标,也是需要操作一定的时间和数量之后才能被发现的。我们也经常能通过自动化测试发现一些更严重的可靠性问题,比如浏览器进程的意外终止。
按照测试场景和时间分
按照测试场景和时间来分,测试方法分为压力测试和长时间测试。
- 压力测试
对于一些关键功能点,我们需要将它们分离出来,进行单独的压力测试。压力测试通常是对某个相对独立的功能点进行重复的页面操作,并观察其对浏览器进程的影响。这样做的目的是为了确保那些基本的、关键的、以及使用频率较高的功能点能够得到充足的测试,从而确保达到最高的可靠性。这样做的好处也很明显,当测试过程发现问题的时候,比较容易进行调试和分析,因为被测功能单一并且相对独立,我们很容易知道是什么样的操作引起的问题。而且,由于功能点的分离,使每一个压力测试都比较短小,一般在 1 到 3 个小时就可以发现问题。
- 长时间测试
在所有的压力测试都完成并且确保没有严重的可靠性问题之后,我们就会进行长时间测试。我们在测试中要覆盖几乎所有已经通过压力测试的功能点。长时间测试一般都会持续较长的时间(比如 24 小时或是更久),所以都是通过自动化工具完成的。测试脚本执行的同时,使用监测工具监测和记录浏览器进程各计数器的变化。根据日志文件和内存增长趋势图来进行分析。
测试工具
对浏览器端进行可靠性测试,我们主要需要两种测试工具。一种是用来模拟页面操作的 GUI 自动化测试工具,一种是用来监测浏览器进程的监测工具。另外,对于测试后的分析工作,我们也需要相应的分析工具。
GUI 自动化测试工具
GUI 自动化测试工具有很多种,我们常用的工具主要是 Rational Functional Tester。
进程监测工具
对于 Windows 操作系统来说,我们通常使用两种工具来进行进程监测:
- Task Manager,这个工具通常在手工测试中被使用,来监测浏览器进程的内存和 CPU 占用。
- System Monitor,我们在自动化测试中使用它,通过加入指定的计数器来监测浏览器进程 的内存和 CPU 使用等信息,并保留日志在硬盘上。也可以通过这个工具直接展示各个 计数器的趋势图。
对于使用 Linux 或其他的操作系统的用户,也可以找到相应的工具对浏览器进行监测。
分析工具
有了以上工具,我们就可以执行我们的测试,并且发现一些浏览器端的可靠性缺陷。一旦发现了问题,我们需要使用工具来做必要的分析。
介绍几款常用的分析工具:
1. Firebug:是 Mozilla Firefox 浏览器的开源扩展,提供了很多功能,可以监视、编辑和调试任何 Web 站点的级联样式表(CSS)、HTML、文档对象模型(DOM)和 JavaScript。Firebug 包括一个 JavaScript 控制台、一个日志记录 API 以及一种有用的网络监视器。借助 Firebug,可以很轻松地调试和优化 Web 和 Ajax 应用程序。
2. sIEve:是一个专门针对 Internet Explorer 浏览器的内存泄露监测工具,是一款开源软件。它可以帮助我们列出当前页面内所有 DOM 节点的基本信息,以及页面内所有 DOM 节点的高级信息,可以查找出页面中的孤立节点,查找出页面中的循环引用等等。
3.JavaScript memory leak detector:是 IE 浏览器的插件,由微软的内部员工开发,功能看起来比 sIEve 要强大。 它可以报告可疑的内存泄露,包括泄露的 DOM 对象,引起泄漏的引用代码和代码出处。但是这个工具只是对于简单的 JavaScript 代码比较好用,对于一些复杂的代码,如使用了 dojo 工具包的 JavaScript 代码,即使发生了内存泄露,也很难定位到引起泄漏的代码,所以很难派上用场。
测试过程中的常见问题
在不同浏览器下进行测试
大多数 web 应用,都会支持一些主流的浏览器,比如 IE,Firefox, Safari 等等。对 web 应用所支持的浏览器,原则上都要进行浏览器端的可靠性测试。
以下几个方面需要我们在测试中特别注意:
- 浏览器设置对测试的影响
浏览器的设置对测试结果有着重要的影响。比如我们是否需要在测试前清除 cache,是否需要清除私有数据,浏览器打开链接是使用标签页还是新窗口,浏览器最小化的时候是否需要释放内存,等等,都根据我们的测试要求进行指定。
- 脚本对测试的影响
同一份脚本在不同的浏览器下运行多少会遇到些问题,需要做相应的修改。健壮的能跨浏览器运行的测试脚本是我们的目标。通过一些技巧,可以使测试脚本兼顾到不同的浏览器。比如:查找对象进可能使用一些稳定的属性和值,如 id。对浏览器相关的问题用分支语句进行分别处理,如不同浏览器弹出的证书认证窗口等。
- 监测和分析工具
在不同的操作系统上进行测试的时候,我们可以选择不同的监测工具,在对浏览器进程进行分析时,工具也随着浏览器和操作系统的不同而有所选择。
浏览器端内存泄漏
内存泄漏是浏览器的可靠性测试中最常见的问题,也是我们测试的重点。根据以往的测试经验,大多数的内存泄漏问题出现在 IE 浏览器上。IE 上内存泄漏的主要原因是由于 IE 浏览器的本地对象和 JavaScript 对象使用的垃圾回收机制不同的引起的(IE 本地对象使用 Reference Counting 垃圾回收机制,而 JavaScript 对象则使用的 Mark-and-Sweep 垃圾回收机制,两种对象之间的循环引用就会导致垃圾回收机制失效。我们后面会有文章专门来讲如何发现和分析浏览器端的内存泄漏问题。)
为了便于发现内存泄漏,我们通常会在测试脚本中输出详细的日志信息来记录每一个页面操作,同时使用监测工具监测浏览器进程的内存使用状况。通过两组日志信息的对比和分析,我们可以很清晰地看出内存的增长趋势,也就可以轻松地找出是哪种操作导致的内存泄漏。
使用工具来分析内存泄漏问题也是测试过程中的一个重要环节。一般常用的工具有 sIEve,js Memory leak detector,Firebug 等等。
浏览器 Crash
通常,长时间的页面操作会导致浏览器的内存增加,响应变慢,但是不会造成浏览器 crash。但是,偶尔也会发生浏览器 crash 的情况。比如,严重的内存泄漏导致浏览器内存使用迅速增长,浏览器进程长时间没有响应,造成浏览器进程异常终止。某些特定的操作也可能导致浏览器 crash,这多半是由于产品自身的原因引起的。
自动化测试与手工测试结果不同
当自动化测试与手工测试得到的结果不一致的时候,我们通常考虑下面几个因素的影响。首先,要排除因为操作步骤上的细微差别而导致不同结果的可能。比如,测试脚本中使用键盘操作,而手工测试却使用的拖拽操作等等。然后,要检查测试脚本中是否加入了一些验证点来验证页面的操作。通常情况下,在验证点中,会有一些额外的页面动作,比如移动鼠标,点击等,这些操作也许会带来一定程度的内存消耗。最后,我们还要考虑到,自动化测试工具本身也可能会导致内存泄漏,比如在使用 Rational Functional Tester 的时候,要通过正确使用 unregister() 或 unregisterAll() 方法来释放对象所占用的内存,否则就可能导致浏览器进程分配的内存不能及时释放,不仅使得自动化测试与手工测试的结果产生差异,同时也降低了软件的可靠性。
服务器端异常
我们在一个长时间的测试过程中有可能遇到服务器端的异常,最终导致测试终止。所以,在测试前一定要反复检查服务器端的配置是否正确,比如,LTPA timeout 的时间是否过短,使得测试到一定的时间就退出登录,等等。另外,在发现问题后要认真查看服务器端的日志文件,根据日志中的信息分析是导致出错的原因,以确认是否是产品的缺陷,并做必要的分析。
测试技巧和注意事项
- 测试场景设计
设计测试场景前一定要了解用户的使用习惯和实际场景,并以此为参照。对于压力测试来说,要进可能多地覆盖关键的功能点。而对于长时间测试来说,则要注意不同的操作顺序可能会导致不同的测试结果。
- 在功能测试通过之后再开始浏览器端的可靠性测试
这是浏览器端可靠性测试进入的标准。如果产品的基本功能还存在很多功能问题的时候,可靠性测试是无法开始的。我们通常在某一功能点相对稳定之后就开始对这一功能点的压力测试。
- 测试客户端使用虚拟机
因为我们需要对不同的浏览器(操作系统)进行测试,所以,我们需要准备不同的测试客户端。为了节约时间和硬件,我们也可以使用虚拟机来作为我们的测试客户端。这些客户端都似乎相对简单的轻量级的测试环境,主要差别就在操作系统和浏览器上。
- 自由测试的补充
作为补充,我们会在设计的测试场景之外做一些自由测试。比如我们会去测试一些比较复杂的和用户不常使用的功能点,也可能会测试纯键盘的操作给浏览器进程带来的影响。
- 浏览器端可靠性测试面临的挑战
浏览器端可靠性测试是一个新的测试领域,它的发展还需要更多的人来参与。目前,我们在测试中面临一些挑战。比如:
- 浏览器的种类繁多,而且不同浏览器之间无论在配置上,显示上,还是对脚本的处理上都有所差异。
- 对于相同的浏览器而言,浏览器版本的不断更新,也促使我们在测试中做相应的应对。
- 目前针对浏览器端内存泄露进行分析的工具还很有限。
- 测试工具需要进一步满足测试的需要,以方便分析内存增长与操作的关系,并且获取操作的响应时间。
- 测试中浏览器的环境与真实客户环境的差异。比如网络,浏览器插件等因素。
- 本文转自<https://www.ibm.com/developerworks/cn/web/1106_hujj_browsertest1/>
Web 2.0 浏览器端可靠性测试第1部分(浏览器端可靠性测试的概念和背景)的更多相关文章
- Web 2.0 浏览器端可靠性测试第2部分(如何发现和分析 Web 2.0 浏览器端的内存泄漏)
介绍浏览器端的可靠性测试 在上一编文章中我们介绍了浏览器端可靠性测试的概念.测试方法.以及常用的测试和分析工具.我们知道,浏览器端可靠性测试,就是以浏览器为测试平台,通过模拟用户在真实场景下的页面操作 ...
- 【饿了么】—— Vue2.0高仿饿了么核心模块&移动端Web App项目爬坑(三)
前言:接着上一篇项目总结,这一篇是学习过程记录的最后一篇,这里会梳理:评论组件.商家组件.优化.打包.相关资料链接.项目github地址:https://github.com/66Web/ljq_el ...
- Web测试要点 做移动端的测试,也做web端的测试,甚至后面桌面端的测试和后台的测试也做了,基本上把我们产品各个端都玩了一轮
Web测试要点 一.功能测试 1.链接测试 (1).测试所有链接是否按指示的那样确实链接到了该链接的页面: (2).测试所链接的页面是否存在: (3).保证Web应用系统上没有孤立的页面(所谓孤立 ...
- web测试要点、方法_web端测试大全总结
一.功能测试 1.1链接测试 链接是web应用系统的一个很重要的特征,主要是用于页面之间切换跳转,指导用户去一些不知道地址的页面的主要手段,链接测试一般关注三点: 1)链接是否按照既定指示那样,确实链 ...
- 语义网 (Semantic Web)和 web 3.0
语义网=有意义的网络. "如果说 HTML 和 WEB 将整个在线文档变成了一本巨大的书,那么 RDF, schema, 和 inference languages 将会使世界上所有的数据变 ...
- O'Reilly总裁提姆-奥莱理:什么是Web 2.0
O'Reilly总裁提姆-奥莱理:什么是Web 2.0 译者序:Web 2.0这一概念,由O'Reilly媒体公司总裁兼CEO提姆·奥莱理提出.他是美国IT业界公认的传奇式人物,是“开放源码”概念的缔 ...
- Django---Http协议简述和原理,HTTP请求码,HTTP请求格式和响应格式(重点),Django的安装与使用,Django项目的创建和运行(cmd和pycharm两种模式),Django的基础文件配置,Web框架的本质,服务器程序和应用程序(wsgiref服务端模块,jinja2模板渲染模块)的使用
Django---Http协议简述和原理,HTTP请求码,HTTP请求格式和响应格式(重点),Django的安装与使用,Django项目的创建和运行(cmd和pycharm两种模式),Django的基 ...
- 说说web 2.0生态圈的那些事
先来说一道面试题吧,“说一下,web 2.0 和web 1.0的区别?” 官方的解释是这样的: Web1.0 的主要特点在于用户通过浏览器获取信息,Web2.0 则更注重用户的交互作用,用户既是网站内 ...
- 大佬福利之在你眼中 Web 3.0 是什么?(转)
web 3.0 Web 3.0一词包含多层含义,用来概括互联网发展过程中某一阶段可能出现的各种不同的方向和特征.Web 3.0 充满了争议和分歧,它到底应该什么样?具体的标志点又是什么? Web 2. ...
随机推荐
- 形式化验证工具(PAT)羊车门代码学习
首先介绍一下PAT工具,下图是PAT工具的图标 PAT工具全称是Process Analysis Toolkit,可以做一些简单的验证. 今天我们分析一下例子里面的Monty Hall Problem ...
- spark 1.5的hivecontext的问题
spark升级到1.5,里面的hive版本升级到1.2.1版本,我写了如下的代码 object SQLApp extends App{ val sparkconf = new SparkConf(). ...
- HDU 2102 A计划 (BFS或DFS)
题意:中文题. 析:是一个简单的搜索,BFS 和 DFS都可行, 主要是这个题有一个坑点,那就是如果有一层是#,另一个层是#或者*,都是过不去的,就可以直接跳过, 剩下的就是一个简单的搜索,只不过是两 ...
- 验证视图状态MAC失败的解决办法
在网上搜寻了很久看了很多关于MAC验证视图状态失败的解决方法.大部分人都说是在页里或web.config里加 EnableEventValidation="false" Enabl ...
- metasploit 读书笔记-EXPLOITATION
一、渗透攻击基础 1.常用命令 show exploits 显示Meta框架中所有可用的渗透攻击模块。 show options 显示模块所需要的各种参数 back 返回Meta的上一个状态 sear ...
- tomcat - 认识
tomcat - web应用服务器 环境:ubuntu测试 @shell命令(cd到tomcat目录下) 启动: ./bin startup.sh 关闭:./bin shutdown.sh @部署 ...
- Mysql union
union简单来说就是多表链接,主要是用于(模糊)查询,全库搜索 多表搜索需要先将需要查询的表用union连接,然后在每一个union后面添加上相同的where条件 菜鸟教程
- 【转】PHP微信上传永久图片素材
$TOKEN="XXXX"; $file = "D:\www\weixin\game.jpg"; $data = array( 'media'=> new ...
- MVC(Java , C# ,php)
- 洛谷P1894 [USACO4.2]完美的牛栏The Perfect Stall
题目描述 农夫约翰上个星期刚刚建好了他的新牛棚,他使用了最新的挤奶技术.不幸的是,由于工程问题,每个牛栏都不一样.第一个星期,农夫约翰随便地让奶牛们进入牛栏,但是问题很快地显露出来:每头奶牛都只愿意在 ...