什么是WebService?
假如有两个国家,
java国和.net国;两国为了发展经济,互通贸易,需要交流,但java国说的是java语言,.net国说的.net语言。为了方便交流,创造了第三方语言WebService。这样说不准确,WebService不是一个语言;暂时先这样理解。
让这两国人民全为了贸易,再全新的
学习一门语言,他们不乐意了。自己国的语言说的好好的,干嘛要费那么大力气再学一个语言。 那能不能造出个电子产品来完成这种功能?从表面上来理解:WebService 就是一个应用程序,它向外界暴露出一个能够通过Web进行调用的API。你能够用编程的方法通过Web来调用这个应用程序。当然,不能把把这个电子产品理解一为一个通用的东西,我们做
手机外贸的,要做具有手机相关于功能的电子产品(应用程序)。你做衣服外贸的,要做具有衣服相关功能的电子产品。也可以这样理解:Web service平台是一套标准,它定义了应用程序如何在Web上实现互操作性。你可以用任何你喜欢的语言,在任何你喜欢的平台上写Web service ,只要我们可以通过Web service标准对这些服务进行查询和访问。
两国人民打算要做这么个东西,那就要来制定这个东西的规范,不是java国作出来的东西,.net国的人怎么知道它是什么玩意,有什么功能。对吧。Web service平台必须提供一套标准的类型系统,用于沟通不同平台、编程语言和组件模型中的不同类型系统。Web service平台也必须提供一种标准来描述Web service,让客户可以得到足够的信息来调用这个Web service。最后,我们还必须有一种方法来对这个Web service进行远程调用。这种方法实际是一种远程过程调用协议(RPC)。
好了,两国人民既然要来制定这个规范,那就坐下来具体说说,应该怎么制定吧!
XML和XSD
可扩展的标记语言(XML)是Web service平台中表示数据的基本格式。除了易于建立和易于分析外,XML主要的优点在于它既是平台无关的,又是厂商无关的。无关性是比技术优越性更重要的:软件厂商是不会选择一个由竞争对手所发明的技术的。
XML解决了数据表示的问题,但它没有定义一套标准的数据类型,更没有说怎么去扩展这套数据类型。例如,整形数到底代表什么?16位,32位,还是64位?这些细节对实现互操作性都是很重要的。W3C制定的XML Schema(XSD)就是专门解决这个问题的一套标准。它定义了一套标准的数据类型,并给出了一种语言来扩展这套数据类型。Web service平台就是用XSD来作为其数据类型系统的。当你用某种语言(如VB.NET或C#)来构造一个Web service时,为了符合Web service标准,所有你使用的数据类型都必须被转换为XSD类型。你用的工具可能已经自动帮你完成了这个转换,但你很可能会根据你的需要修改一下转换过程。在第二章中,我们将深入XSD,学习怎样转换自定义的数据类型(例如类)到XSD的类型。
SOAP
Web service建好以后,你或者其他人就会去调用它。简单对象访问协议(SOAP)提供了标准的RPC方法来调用Web service。实际上,SOAP在这里有点用词不当:它意味着下面的Web service是以对象的方式表示的,但事实并不一定如此:你完全可以把你的Web service写成一系列的C函数,并仍然使用SOAP进行调用。SOAP规范定义了SOAP消息的格式,以及怎样通过HTTP协议来使用SOAP。SOAP也是基于XML和XSD的,XML是SOAP的数据编码方式。
WSDL
你会怎样向别人介绍你的Web service有什么功能,以及每个函数调用时的参数呢?你可能会自己写一套文档,你甚至可能会口头上告诉需要使用你的Web service的人。这些非正式的方法至少都有一个严重的问题:当程序员坐到电脑前,想要使用你的Web service的时候,他们的工具(如Visual Studio)无法给他们提供任何帮助,因为这些工具根本就不了解你的Web service。解决方法是:用机器能阅读的方式提供一个正式的描述文档。Web service描述语言(WSDL)就是这样一个基于XML的语言,用于描述Web service及其函数、参数和返回值。因为是基于XML的,所以WSDL既是机器可阅读的,又是人可阅读的,这将是一个很大的好处。一些最新的开发工具既能根据你的Web service生成WSDL文档,又能导入WSDL文档,生成调用相应Web service的代码。
好吧!我想我们大体的了解了WebService是什么东西,再来理解WebService性能,你写好的一个WebService的应用程序的接口放那里,会有好多人来调用,当然会有质量问题了。人多的时候,会不会有不成功啊?会不会慢啊?所以要 对这个“接口”做
性能测试。
其实有不懂的地方,我发送什么样的请求来调用那个“接口”做测试,soapUI是自动帮我们完成SOAP协议请求的!由于刚接触这个工具,希望一高手指点学习。
import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import android.app.Activity; import android.os.AsyncTask; import android.os.Bundle; import android.util.Log; public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); new NetPing().execute(); } public String Ping(String str) { String resault = ""; Process p; try { //ping -c 3 -w 100 中 ,-c 是指ping的次数 3是指ping 3次 ,-w 100 以秒为单位指定超时间隔,是指超时时间为100秒 p = Runtime.getRuntime().exec("ping -c 3 -w 100 " + str); int status = p.waitFor(); InputStream input = p.getInputStream(); BufferedReader in = new BufferedReader(new InputStreamReader(input)); StringBuffer buffer = new StringBuffer(); String line = ""; while ((line = in.readLine()) != null){ buffer.append(line); } System.out.println("Return ============" + buffer.toString()); if (status == 0) { resault = "success"; } else { resault = "faild"; } } catch (IOException e) { e.printStackTrace(); } catch (InterruptedException e) { e.printStackTrace(); } return resault; } private class NetPing extends AsyncTask<String, String, String> { @Override protected String doInBackground(String... params) { String s = ""; s = Ping("www.baidu.com"); Log.i("ping", s); return s; } } } |
!!!别忘了加访问网络权限!!!
下面是运行截图:
如果对 运行结果中的 PING www.a.shifen.com (61.135.169.125) 感到怀疑,那么可以试一下 61.135.169.125 就是百度的网址。
suceess则表示连接成功
如果当前没有连接网络,return 会是 空的 ,结果会是 faild。
如果ping的网址是不存在的,而且还连接着网络,那么程序就会 停在
int status = p.waitFor();
这里,不再向下运行。
Ping远程IP
这一命令可以检测本机能否正常访问Internet。比如本地电信运营商的IP地址为:202.101.224.69。在MS-DOS方式下执行命令:Ping 202.101.224.69,如果屏幕显示:
C:\Documents and Settings\Administrator>ping 202.101.224.69 Pinging 202.101.224.69 with 32 bytes of data: Reply from 202.101.224.69: bytes=32 time=2ms TTL=250 Reply from 202.101.224.69: bytes=32 time=2ms TTL=250 Reply from 202.101.224.69: bytes=32 time=3ms TTL=250 Reply from 202.101.224.69: bytes=32 time=2ms TTL=250 Ping statistics for 202.101.224.69: Packets: Sent = 4, Received = 4, Lost = 0 (0% loss), Approximate round trip times in milli-seconds: Minimum = 2ms, Maximum = 3ms, Average = 2ms |
则表明运行正常,能够正常接入互联网。反之,则表明主机文件(windows/host)存在问题。
介绍
每个实行持续交付的项目,都有生产流水线的元素,如持续集成和
自动化测试。这些测试是在不同层面进行的,从
单元测试到冒烟测试再到
功能测试。自动化功能测试的优点之一是可重复性和可预测的执行时间。出于这个原因,它应该作为软件质量的每一个构建之后的指标。功能测试自动化往往会成为一个瓶颈,所以你应该熟悉一下如何创建这样的测试的基本原则。
首先设计你的测试
测试集合可以比作盆景树。
最初的时候,我们照顾树根和树干。我们选择会成长的主要分支,我们每天都细心照料这棵树并等待它长出健康的叶子。
我们可以以类似的方式继续测试。
我们建一个将负责应用程序主要功能(例如:开启)的基类。
根据说明,我们先明确将被测试覆盖的应用程序的主要功能,然后每天我们在执行测试的时候都添加更多平行测试。
每一个支持测试(例如创建一个新的用户)的方法都需要与测试分离——让我们在单独的类里面来实现。
你应该在包括了应用程序主要功能的目录里保持类。
去建一个规定很多功能共有方法的抽象类是很好的做法。
如果你正在测试Web应用程序,就用页面对象设计模式。该模式里,一个类及其方法对应了单个页面的功能或一个大型网页里单个页面上的一个元素。
无需事事自动化
自动化花费很多,所以你应该主要测试应用程序的主要功能。
某些测试可以快速轻松地手动完成,且潜在脚本可能难以实现。
值得用到自动化的是那些繁琐的需要被重复很多次的,和那些需要大量数据验证的测试
工作。
写短测试
在一个或多个测试失败的情况下,开发团队的任何成员都应该能够轻松地找到错误的原因。
出于这个原因,每个测试方法里应该最多有5个断言,并且每个方法都必须提供的测试操作的完整记录。
明智的做法是使用BDD(行为驱动开发)技术,但是当你没有用一个特定的测试框架时,你应该把接下来的测试步骤放在comments //given //when //then下。
创建独立测试
在测试类中的每个方法应该是一个独立的实体,而不是依赖于其他测试。我们应该能够在任何时间运行单个测试。否则,这样的
测试用例集将来维护起来就会很贵——必须定期跟踪和更新测试之间的联系。
很多时候,测试需要一定的前提条件来满足。这些条件不应该用外部方法,应该在试验开始时运行。如果这些条件和测试类的所有方法一样,它们就可以被放在一开始进行的方法里(例如:在
JUnit中被标记为@ BeforeClass)。
关注可读性
源代码应该是自我记录的,而写下以下几行代码的每个利益相关者应该明白测试在做什么,为什么它被这么写。尽量避免在源代码注释,因为它也必须被更新。这值得花比平常多一点的时间来命名方法,从而使你的代码更易读。
再看看行为驱动开发技术,每个测试方法都应以单词“应该”开始,而不是“测试”。
根据这一惯例,我们马上就可以明白一个特定的方法测试什么内容了,它在分析测试报告时特别有用。
测试必须要快
正如在本文开头所提到的,自动化功能测试应该是应用程序质量的一个指标。连续传递过程中的每一步都应指明最长持续时间;并且根据这个概念,开发团队应该尽快获得有关软件质量的反馈。自动化功能测试的持续时间应不超过几分钟。
对一个非常全面的测试集来说,有必要并行运行测试(经常在不同的机器上)。虚拟化在这里可能是非常有帮助的。
创建抗变测试
最常提及自动化功能测试的缺点是其对应用程序中变化的低抵抗性,尤其是在GUI中。
在Web应用程序中,测试应该能抵抗网站的内容的变化。测试应该只验证功能,这就使得它可以在不同的位置运行测试。这并不意味着我们不应该编写自动化测试来检查网页的内容。
如果你已经想创建这样的测试,你应该遵循DDT(数据驱动测试)技术。这意味着,检查内容是与源代码分离开的。
Web应用程序的页面布局变化非常频繁,这已经影响到了用户界面。
当你设计一个界面时,每个区段和每个页面你都应该有一个你可以用来测试的唯一标识符,即使一个网站的层次结构发生了变化。
自动化测试无法取代人类
功能自动化测试可以是项目中的主要测试技术,但绝不是唯一的一个。
自动化测试是可重复再生的,他们的覆盖范围总是相同的。
另一方面,虽然探索性测试是低再生的,但是它们能够覆盖自动化测试未触及的区域。
你还应该记住,自动化测试的“绿色”状态并不意味着你的应用程序是没有错误的。
这种情况往往会让测试员分心,而且有可能会影响测试的准确性。
花了两天的时间来安装
Oracle数据库,中间遇到很多的问题,例如 ORA-12541,ORA-12154各种各样的问题,开始都是搜这种错误的解决方法,最后弄得越来越复杂,越来越难解决,最后才恍然大悟。原来是因为自己对于Oracle数据库连皮毛都不懂,根本就不知道数据库的运行流程,不能正确的认识装Oracle时所遇到的各种问题。
现把Oracle 12C的安装步骤写下:
1.首先是安装12C数据库,只要按照
百度文库里面的
文章进行安装就应该能成功。
百度文库12C安装参考
2.在安装完成后,对中间设置的一些用户名和口令应该有一个整体的了解,这队了解Oracle数据库非常有用。
1)里面的windows用户口令,用于在建立新的数据库的主目录登陆验证口令(只有知道这个口令才能正确的添加数据库)
2)在安装的过程中会建立一个数据库,但是一帮情况下这个数据库是没有配置任何监听端口的,所以在连接这个数据库的时候,若是出现无监听端口,不要着急的修改什么配置文件,只需要确定你的监听端口服务是开启的,就说明你的数据库安装基本没有什么大的问题。
3.在整体安装完成后,用数据库自带的数据库配置工具就可以添加数据库,这个时候你可以设置你想要的数据库名字,SID,口令等等,在这个里面会出现你想使用的监听接口名字,配置完这个后就基本不会再出现无监听端口的情况了。
4.在整个过程完成后,其实数据库中解锁了两个用户,SYSTEM/SYS,这两个用户都是具有较高的用户权限,要使用一个全新的数据库,还需要在你创建的全局数据库下面添加用户。具体添加方法如下:
方法一:
C:\Documents and Settings\ssy>sqlplus sys/密码@数据库名称 as sysdba SQL*Plus: Release 9.2.0.1.0 - Production on 星期一 3月 17 18:01:41 2008 Copyright (c) 1982, 2002, Oracle Corporation. All rights reserved. 连接到: Oracle9i Enterprise Edition Release 9.2.0.1.0 - Production With the Partitioning, OLAP and Oracle Data Mining options JServer Release 9.2.0.1.0 - Production |
方法二:
C:\Documents and Settings\ssy>sqlplus /nolog SQL*Plus: Release 9.2.0.1.0 - Production on 星期一 3月 17 17:59:08 2008 Copyright (c) 1982, 2002, Oracle Corporation. All rights reserved. SQL> conn sys/密码@数据库名称 as sysdba 已连接。 create user cmsuser identified by "cmsuser"; SQL> create user uumcuser identified by "password"; User created. SQL> grant connect,dba to uumcuser; Grant succeeded. SQL> grant exp_full_database,imp_full_database,resource,create any sequence to cmsuser; Grant succeeded. SQL> grant create any trigger,create any view,create table,drop any view to uumcuser; Grant succeeded. SQL> grant exp_full_database,imp_full_database,resource,create any sequence to uumcuser; Grant succeeded. |
5.在使用navicat for Oracle软件的时候会出现network admin err的问题,这是因为oci.DLL的问题,需要安装一个Oracle的客户端Instant Client,用于连接Oracle 和navicat。安装完之后,打开Navicat的工具--配置--oci,选择 Client下面的OCI,这个时候Navicat就能正常使用了。
到此真个Oracle完全安装完毕,花费了两天的时间,中间烦躁过,放弃过,其实坚持过来才知道自己已经了解了很多的东西。
首先来看一张图,下面这张图很清晰的说明了线程的状态与Thread中的各个方法之间的关系,很经典的!
在
Java中创建线程有两种方法:使用Thread类和使用Runnable接口。
要注意的是Thread类也实现了Runnable接口,因此,从Thread类继承的类的实例也可以作为target传入这个构造方法。可通过这种方法实现多个线程的资源共享。
线程的生命周期:
1.新建状态(New):用new语句创建的线程对象处于新建状态,此时它和其它的java对象一样,仅仅在堆中被分配了内存
2.就绪状态(Runnable):当一个线程创建了以后,其他的线程调用了它的start()方法,该线程就进入了就绪状态。处于这个状态的 线程位于可运行池中,等待获得CPU的使用权
3.运行状态(Running): 处于这个状态的线程占用CPU,执行程序的代码
4.阻塞状态(Blocked): 当线程处于阻塞状态时,java虚拟机不会给线程分配CPU,直到线程重新进入就绪状态,它才有机会转到 运行状态。
阻塞状态分为三种情况:
1)、 位于对象等待池中的阻塞状态:当线程运行时,如果执行了某个对象的wait()方法,java虚拟机就回把线程放到这个对象的等待池中
2)、 位于对象锁中的阻塞状态,当线程处于运行状态时,试图获得某个对象的同步锁时,如果该对象的同步锁已经被其他的线程占用,JVM就会把这个线程放到这个对象的琐池中。
3)、 其它的阻塞状态:当前线程执行了sleep()方法,或者调用了其它线程的join()方法,或者发出了I/O请求时,就会进入这个状态中。
一、创建并运行线程
当调用start方法后,线程开始执行run方法中的代码。线程进入运行状态。可以通过Thread类的isAlive方法来判断线程是否处于运行状态。当线程处于运行状态时,isAlive返回true,当isAlive返回false时,可能线程处于等待状态,也可能处于停止状态。
二、挂起和唤醒线程
一但线程开始执行run方法,就会一直到这个run方法执行完成这个线程才退出。但在线程执行的过程中,可以通过两个方法使线程暂时停止执行。这两个方法是suspend和sleep。在使用suspend挂起线程后,可以通过resume方法唤醒线程。而使用sleep使线程休眠后,只能在设定的时间后使线程处于就绪状态(在线程休眠结束后,线程不一定会马上执行,只是进入了就绪状态,等待着系统进行调度)。
虽然suspend和resume可以很方便地使线程挂起和唤醒,但由于使用这两个方法可能会造成一些不可预料的事情发生,因此,这两个方法被标识为deprecated(弃用)标记,这表明在以后的jdk版本中这两个方法可能被删除,所以尽量不要使用这两个方法来操作线程。
三、终止线程的三种方法
有三种方法可以使终止线程。
1. 使用退出标志,使线程正常退出,也就是当run方法完成后线程终止。
2. 使用stop方法强行终止线程(线程中调用了阻塞代码)(这个方法不推荐使用,因为stop是依靠抛出异常来结束线程的,也可能发生不可预料的结果)。如果没有调用阻塞代码,可以正常结束线程。
3. 使用interrupt方法中断线程(线程中调用了阻塞代码)(其实这种方法也是通过抛出异常来结束线程的)。如果没有调用阻塞代码,可以通过判断线程的中断标志位来介绍线程。
线程的几个方法:
join():等待此线程死亡后再继续,可使异步线程变为同步线程
interrupt():中断线程,被中断线程会抛InterruptedException
wait():等待获取锁:表示等待获取某个锁执行了该方法的线程释放对象的锁,JVM会把该线程放到对象的等待池中。该线程等待其它线程唤醒
notify():执行该方法的线程唤醒在对象的等待池中等待的一个线程,JVM从对象的等待池中随机选择一个线程,把它转到对象的锁池中。使线程由阻塞队列进入就绪状态
sleep():让当前正在执行的线程休眠,有一个用法可以代替yield函数——sleep(0)
yield():暂停当前正在执行的线程对象,并执行其他线程。也就是交出CPU一段时间(其他同样的优先级或者更高优先级的线程可以获取到运行的机会) sleep和yield区别:
1、sleep()方法会给其他线程运行的机会,而不考虑其他线程的优先级,因此会给较低线程一个运行的机会;yield()方法只会给相同优先级或者更高优先级的线程一个运行的机会。
2、当线程执行了sleep(long millis)方法后,将转到阻塞状态,参数millis指定睡眠时间;当线程执行了yield()方法后,将转到就绪状态。
3、sleep()方法声明抛出InterruptedException异常,而yield()方法没有声明抛出任何异常
4、sleep()方法比yield()方法具有更好的移植性
如果希望明确地让一个线程给另外一个线程运行的机会,可以采取以下的办法之一:
1、调整各个线程的优先级
2、让处于运行状态的线程调用Thread.sleep()方法
3、让处于运行状态的线程调用Thread.yield()方法
4、让处于运行状态的线程调用另一个线程的join()方法
首先,wait()和notify(),notifyAll()是Object类的方法,sleep()和yield()是Thread类的方法。
(1).常用的wait方法有wait()和wait(long timeout):
void wait() 在其他线程调用此对象的 notify() 方法或 notifyAll() 方法前,导致当前线程等待。
void wait(long timeout) 在其他线程调用此对象的 notify() 方法或 notifyAll() 方法,或者超过指定的时间量前,导致当前线程等待。
wait()后,线程会释放掉它所占有的“锁标志”,从而使线程所在对象中的其它synchronized数据可被别的线程使用。
wait()和notify()因为会对对象的“锁标志”进行操作,所以它们必须在synchronized函数或synchronized代码块中进行调用。如果在non- synchronized函数或non-synchronized代码块中进行调用,虽然能编译通过,但在运 行时会发生IllegalMonitorStateException的异常。
(2).Thread.sleep(long millis),必须带有一个时间参数。
sleep(long)使当前线程进入停滞状态,所以执行sleep()的线程在指定的时间内肯定不会被执行;
sleep(long)可使优先级低的线程得到执行的机会,当然也可以让同优先级和高优先级的线程有执行的机会;
sleep(long)是不会释放锁标志的。
(3).yield()没有参数。
sleep 方法使当前运行中的线程睡眼一段时间,进入不可运行状态,这段时间的长短是由程序设定的,yield 方法使当前线程让出CPU占有权,但让出的时间是不可设定的。yield()也不会释放锁标志。
实际上,yield()方法对应了如下操作: 先检测当前是否有相同优先级的线程处于同可运行状态,如有,则把 CPU 的占有权交给此线程,否则继续运行原来的线程。所以yield()方法称为“退让”,它把运行机会让给了同等优先级的其他线程。
sleep方法允许较低优先级的线程获得运行机会,但yield()方法执行时,当前线程仍处在可运行状态,所以不可能让出较低优先级的线程些时获得CPU占有权。 在一个运行系统中,如果较高优先级的线程没有调用 sleep 方法,又没有受到 I/O阻塞,那么较低优先级线程只能等待所有较高优先级的线程运行结束,才有机会运行。
yield()只是使当前线程重新回到可执行状态,所以执行yield()的线程有可能在进入到可执行状态后马上又被执行。所以yield()只能使同优先级的线程有执行的机会。
volitile 语义
volatile相当于synchronized的弱实现,也就是说volatile实现了类似synchronized的语义,却又没有锁机制。它确保对volatile字段的更新以可预见的方式告知其他的线程。
volatile包含以下语义:
(1)Java 存储模型不会对valatile指令的操作进行重排序:这个保证对volatile变量的操作时按照指令的出现顺序执行的。
(2)volatile变量不会被缓存在寄存器中(只有拥有线程可见)或者其他对CPU不可见的地方,每次总是从主存中读取volatile变量的结果。也就是说对于volatile变量的修改,其它线程总是可见的,并且不是使用自己线程栈内部的变量。也就是在happens-before法则中,对一个valatile变量的写操作后,其后的任何读操作理解可见此写操作的结果。
尽管volatile变量的特性不错,但是volatile并不能保证线程安全的,也就是说volatile字段的操作不是原子性的,volatile变量只能保证可见性(一个线程修改后其它线程能够理解看到此变化后的结果),要想保证原子性,目前为止只能加锁!
数据同步:
线程同步的特征:
1、如果一个同步代码块和非同步代码块同时操作共享资源,仍然会造成对共享资源的竞争。因为当一个线程执行一个对象的同步代码块时,其他的线程仍然可以执行对象的非同步代码块。(所谓的线程之间保持同步,是指不同的线程在执行同一个对象的同步代码块时,因为要获得对象的同步锁而互相牵制)
2、每个对象都有唯一的同步锁
3、在静态方法前面可以使用synchronized修饰符,但是要注意的是锁对象是类(用Object.class而不能用this),而不是这个类的对象。
4、当一个线程开始执行同步代码块时,并不意味着必须以不间断的方式运行,进入同步代码块的线程可以执行Thread.sleep()或者执行Thread.yield()方法,此时它并不释放对象锁,只是把运行的机会让给其他的线程。
5、synchronized声明不会被继承,如果一个用synchronized修饰的方法被子类覆盖,那么子类中这个方法不在保持同步,除非用synchronized修饰。
6、synchronized 关键字能够修饰一个对象实例中的函数或者代码块。 在一个非静态方法中 this 关键字表示当前的实例对象。 在一个 synchronized 修饰的静态的方法中,这个方法所在的类使用 Class 作为实例对象
(1)Tsung的每一个虚拟用户就是一个erlang的轻量进程。这点和loadrunner有很大的区别。
(2)虚拟用户完成session后就消失。
(3)大量的虚拟用户(erlang轻量进程)建立在erlangVM上。
(4)一台
测试机可以启多个erlangVM,目前按照1个cpu启动1个erlangVM。
分布式部署Tsung在运行时,会产生ssl_esock、beam、beam.smp3种进程,ssl-esock是erlangVM用的port程序, 协助完成ssh功能;beam是单处理器版本的erlangVM;beam.smp就是control程序,负责协调系统的运作。
这一篇我的偶像Jackei 致敬:
(关于偶像的问题,发表一下自己的看法,我觉得每个人都应该有“偶像”,偶像是标杆和奋斗目标。关于有些人拿比尔盖茨 和 自己当偶像的,要么活在梦里,要么活在自己的世界,我只能 呵呵 了。)
其实,从刚开始做
测试就有
学习自动化(基于UI 的
web自动动化测试),理解上一直处于非常皮毛的状态。再次的深入学习并实践自动化大概从半年前开始。边学习边总结是我的一贯学习方式。
《我所知道的
软件测试自动化》- 关键字驱动的过去和未来
Jackei 的这篇
文章我了好几遍,虽然将的内容并不高深,但随着自己自动化水平的提高,每次看完也会一新体会。基于这篇文章,扩展的来谈一下自己对几种
自动化测试模型的理解。
线性测试
通过录制或编写脚本,一个脚本完成用户一套完整的操作,通过对脚本的回放来进行自动化测试。
这是早期进行自动化测试的一种形式。
脚本一
from selenium import webdriver import time driver = webdriver.Firefox() driver.get("http://passport.cnblogs.com/login.aspx?ReturnUrl=http://www.cnblogs.com/fnng/admin/EditPosts.aspx") driver.find_element_by_id("tbUserName").send_keys("admin") driver.find_element_by_id("tbPassword").send_keys("123456") driver.find_element_by_id("btnLogin").click() ...... driver.quit () |
脚本二
from selenium import webdriver import time driver = webdriver.Firefox() driver.get("http://passport.cnblogs.com/login.aspx?ReturnUrl=http://www.cnblogs.com/fnng/admin/EditPosts.aspx") driver.find_element_by_id("tbUserName").send_keys("user") driver.find_element_by_id("tbPassword").send_keys("456123") driver.find_element_by_id("btnLogin").click() ...... driver.quit () |
通过上面的两个脚本,我们很明显的发现它的问题:
一个用例对应一个脚本,假如界面发生变化,用户名的属性发生改变,不得不需要对每一个脚本进行修改,
测试用例形成一种规模,我们可能将大量的
工作用于脚本的维护,从而失去自动化的意义。
这种模式下数据和脚本是混在一起的,如果数据发生变也也需要对脚本进行修改。
这种模式下脚本的可重复使用率很低。
模块化与库
我们会清晰的发现在上面的脚本中,其实有不少内容是重复的;于是就有了下面的形式。
#coding=utf-8 from selenium import webdriver import time #登录模块 def login(): driver.find_element_by_id("tbUserName").send_keys("user") driver.find_element_by_id("tbPassword").send_keys("456123") driver.find_element_by_id("btnLogin").click() #退出模块 def quit(): .............. driver = webdriver.Firefox() driver.get("http://passport.cnblogs.com/login.aspx?ReturnUrl=http://www.cnblogs.com/fnng/admin/EditPosts.aspx") #调用登录模块 login() #其它个性化操作 ...... #调用退出模块 |
注意,为了省事我把代码写在了一个文件里,真正的实施时需要把模块放到其它文件进行调用。还有上面代码不能完整运行。
通过上面的代码发现,我们可以把脚本中相同的部分独立出来,形成模块或库;当脚本需要进行调用。这样做有两个好处:
一方面提高了开发效率,不用重复的编写相同的脚本。
另一方面提高了代码的复用。
数据驱动
数据驱动应该是自动化的一个进步;从它的本意来讲,数据的改变(更新)驱动自动化的执行,从而引起结果改变。这显然是一个非常高级的概念和想法。
其实,我们能做到的是下面的形式。
d:\abc\data.txt
#coding=utf-8 from selenium import webdriver import os,time source = open("D:\\abc\\data.txt", "r") values = source.readlines() source.close() # 执行循环 for serch in values: browser = webdriver.Firefox() browser.get("http://www.baidu.com") browser.find_element_by_id("kw").send_keys(serch) browser.find_element_by_id("su").click() browser.quit() |
好吧!不管我们读取的是txt 文件,还是csv、excel 文件的之类,又或者是数组、字典函数。我们实现了数据与脚本的分离,换句话说,我们实现了参数化。我们仍一千条数据,通过脚本的执行,可以返回一千条结果出来。
同样的脚本执行不同的数据从而得到了不同的结构。是不是增强的脚本的复用性呢!
其实,这对开发来说是完全没有什么技术含量的;对于当初QTP 自动化工具来说确是一个买点,因为它面对的大多是不懂开发的测试。
关键字驱动
理解了数据驱动,无非是把“数据”换成“关键字”,关键字的改变引起测试结果的改变。
关键字驱动用编程方式就不太容易表现了。QTP 、 robot framework 等自动化工具就是典型的关键字驱动(填表格)
好吧!我能说selenium IDE 也是关键字驱动么?
转化成表格是这样的:
Selenium IDE 脚本分:命令(command)、对象(command)、值(value)
格式就那里不偏不移,通过这样的格式去描述不同的对象,从而引起最终结果的改变。也就是说一切以对象为出发点。
当然,这样的脚本,显然对于不懂代码的同学非常直观!我要找谁(对象)?怎么做(命令)?做什么(值)?
更高级的关键字驱动,可以自己定义keyword然后“注册”到框架;从而实现更强大的功能和扩展性。关键字更详细的理解可以看我偶像的那偏文章。
本文所列出了不同自动化模型,虽然简单阐述了他们的优缺点,但并不主观的说评判某一模型好坏。其实他们也并非单纯后者淘汰前者的关系,实施自动化更多的是以需求为出发点,混合的来使用以上模型去解决问题。
php远程连接mysql数据库的步骤如下:
1.使用所购买空间的
数据库管理界面,设置远程访问IP,也就是php文件所在的主机IP。
2.php文件中的数据库连接代码如下:
$con = new mysqli($host, $user, $passwd, $database); |
$host:数据库所在主机的IP,这里需要注意的是有的资料说在IP之后需要有“3306”这个端口号,但是我经过
测试发现,加上端口号之后反而连接失败,所以这里不需要加端口号。
当用php连接本地数据库时,令$host = 'localhost'即可,也不需要加端口号。
$user:用户名 $passwd:密码 $database:数据库名 |
3.执行php文件即可成功连接到数据库
另外再补充一点,就是直接使用mysql命令远程连接到数据库:
mysql -h $host -P 3306 -u $user -p |
回车后输入密码即可连接成功