这个是我后来写的一本书,http://www.ituring.com.cn/minibook/10775。这个是我后来找到的自动化完美解决方案。
谈到企业级自动化测试,大家肯定会想到QTP,Ration Robot等自动化测试软件,这些软件无论在成熟度还是在用户认可度上都比较高,但它们都有致命的缺点,1,都需要钱去买且价格不菲。2,并不是专门针对本企业产品所设计,所以会出现测试功能点不能完全涵盖的缺陷。也正是是这些缺点限制了它们你能大范围的使用。
那如何能让自己企业的软件能应用上自动化测试且不受上述缺点的限制呢?一个答案,构建属于自己的企业自动化测试框架。
那我们接下来谈下自动化测试要测试什么, 我以一个购物网站京东商城为例: 比如京东商城是每隔2个月发布一个新版本,那么在新版本即将上线的时候,就要把新版本的所有功能和所有流程手工执行一遍,以确保新版本在发布的时候没有BUG。手工测试的时候最主要测试的三点是什么呢?1,手工点击页面去完成某个流程,如购物,退款等。2,连接上数据库检测下相应的数据库表有没有被正确修改。3,检测下购物网站所特有的业务,比如消息的发送(如购物网站的订单信息发送到客户关系网站让业务人员能完成退单和换地址等功能)。
闲话少说:首先我们来用一段代码来告诉下什么叫自动化。
建一个java工程,百度谷歌下这两个Jar包加入到你的工程中(selenium-java-client-driver.jar,selenium-server.jar),如图所示:
建一个java类:
import org.openqa.selenium.server.RemoteControlConfiguration;
import org.openqa.selenium.server.SeleniumServer;
import com.thoughtworks.selenium.DefaultSelenium;
import com.thoughtworks.selenium.Selenium;
public class TestJingDong {
/**
* @param args
* @throws Exception
*/
public static void main(String[] args) throws Exception {
// 建立并启动Selenium Server
SeleniumServer server;
Selenium selenium;
RemoteControlConfiguration cfg = new RemoteControlConfiguration();
try {
server = new SeleniumServer(cfg);
server.boot();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// 启动Selenium
selenium = new DefaultSelenium("localhost", 4444, "*iexplore",
"http://www.360buy.com/");
selenium.start();
selenium.windowMaximize();
// Selenium 设定页面响应时间最大值
selenium.setTimeout("600000");
// 打开执行页面
selenium.open("http://www.360buy.com/product/286048.html");
//等待20秒等待页面加载
Thread.sleep(20000);
selenium.click("xpath=id('InitCartUrl')");
Thread.sleep(20000);
selenium.click("xpath=id('GotoShoppingCart')");
Thread.sleep(20000);
selenium.click("xpath=id('gotoOrderInfo')");
Thread.sleep(5000);
selenium.type("xpath=id('loginname')", "testjingdongcom");
selenium.type("xpath=id('loginpwd')", "jingdong");
selenium.click("xpath=id('loginsubmitframe')");
Thread.sleep(10000);
selenium.type("xpath=id('consignee_addressName')", "张俊卿");
selenium.select("xpath=id('consignee_province')", "index=2");
Thread.sleep(5000);
selenium.select("xpath=id('consignee_city')", "普陀区*");
Thread.sleep(10000);
selenium.select("xpath=id('consignee_county')", "桃浦新村*");
selenium.type("xpath=id('consignee_address')", "上海西站");
selenium.type("xpath=id('consignee_message')", "13999999999");
selenium
.click("xpath=id('part_consignee')//div[@class='footer']/input");
Thread.sleep(5000);
selenium.check("xpath=id('IdPaymentType1')");
String s = selenium
.getText("xpath=id('part_cart')//div[@class='middle']//tr[@class='align_Center']/td[1]");
System.out.println(s);
}
}
我们能看到,当你执行这个类的时候,这个程序会代替你手工执行页面去京东订购一件商品。
下面是它执行的时候所产生的日志文件。
17:52:46.350 INFO - Preparing Firefox profile...
17:52:50.037 INFO - Launching Firefox...
17:52:56.085 INFO - Got result: OK,f5af93f896a24a5f893c9b1d6b576129 on session f5af93f896a24a5f893c9b1d6b576129
17:52:56.085 INFO - Command request: windowMaximize[, ] on session f5af93f896a24a5f893c9b1d6b576129
17:52:56.100 INFO - Got result: OK on session f5af93f896a24a5f893c9b1d6b576129
17:52:56.100 INFO - Command request: setTimeout[600000, ] on session f5af93f896a24a5f893c9b1d6b576129
17:52:56.116 INFO - Got result: OK on session f5af93f896a24a5f893c9b1d6b576129
17:52:56.116 INFO - Command request: open[http://www.360buy.com/product/286048.html, ] on session f5af93f896a24a5f893c9b1d6b576129
17:53:17.320 INFO - Got result: OK on session f5af93f896a24a5f893c9b1d6b576129
17:53:37.321 INFO - Command request: click[xpath=id('InitCartUrl'), ] on session f5af93f896a24a5f893c9b1d6b576129
17:53:37.352 INFO - Got result: OK on session f5af93f896a24a5f893c9b1d6b576129
17:53:57.353 INFO - Command request: click[xpath=id('GotoShoppingCart'), ] on session f5af93f896a24a5f893c9b1d6b576129
17:53:57.368 INFO - Got result: OK on session f5af93f896a24a5f893c9b1d6b576129
17:54:17.367 INFO - Command request: click[xpath=id('gotoOrderInfo'), ] on session f5af93f896a24a5f893c9b1d6b576129
17:54:17.383 INFO - Got result: OK on session f5af93f896a24a5f893c9b1d6b576129
17:54:22.383 INFO - Command request: type[xpath=id('loginname'), xhyspring] on session f5af93f896a24a5f893c9b1d6b576129
17:54:22.414 INFO - Got result: OK on session f5af93f896a24a5f893c9b1d6b576129
17:54:22.414 INFO - Command request: type[xpath=id('loginpwd'), 19830210] on session f5af93f896a24a5f893c9b1d6b576129
17:54:22.445 INFO - Got result: OK on session f5af93f896a24a5f893c9b1d6b576129
17:54:22.445 INFO - Command request: click[xpath=id('loginsubmitframe'), ] on session f5af93f896a24a5f893c9b1d6b576129
17:54:22.461 INFO - Got result: OK on session f5af93f896a24a5f893c9b1d6b576129
17:54:32.476 INFO - Command request: type[xpath=id('consignee_addressName'), 张俊卿] on session f5af93f896a24a5f893c9b1d6b576129
17:54:33.492 INFO - Got result: OK on session f5af93f896a24a5f893c9b1d6b576129
17:54:33.492 INFO - Command request: select[xpath=id('consignee_province'), index=2] on session f5af93f896a24a5f893c9b1d6b576129
17:54:33.507 INFO - Got result: OK on session f5af93f896a24a5f893c9b1d6b576129
17:54:38.507 INFO - Command request: select[xpath=id('consignee_city'), 普陀区*] on session f5af93f896a24a5f893c9b1d6b576129
17:54:38.523 INFO - Got result: OK on session f5af93f896a24a5f893c9b1d6b576129
17:54:48.616 INFO - Command request: select[xpath=id('consignee_county'), 桃浦新村*] on session f5af93f896a24a5f893c9b1d6b576129
17:54:49.553 INFO - Got result: OK on session f5af93f896a24a5f893c9b1d6b576129
17:54:49.553 INFO - Command request: type[xpath=id('consignee_address'), 上海西站] on session f5af93f896a24a5f893c9b1d6b576129
17:54:49.569 INFO - Got result: OK on session f5af93f896a24a5f893c9b1d6b576129
17:54:49.569 INFO - Command request: type[xpath=id('consignee_message'), 13999999999] on session f5af93f896a24a5f893c9b1d6b576129
17:54:49.585 INFO - Got result: OK on session f5af93f896a24a5f893c9b1d6b576129
17:54:49.585 INFO - Command request: click[xpath=id('part_consignee')//div[@class='footer']/input, ] on session f5af93f896a24a5f893c9b1d6b576129
17:54:49.600 INFO - Got result: OK on session f5af93f896a24a5f893c9b1d6b576129
17:54:54.600 INFO - Command request: check[xpath=id('IdPaymentType1'), ] on session f5af93f896a24a5f893c9b1d6b576129
17:54:54.647 INFO - Got result: OK on session f5af93f896a24a5f893c9b1d6b576129
17:54:54.647 INFO - Command request: getText[xpath=id('part_cart')//div[@class='middle']//tr[@class='align_Center']/td[1], ] on session f5af93f896a24a5f893c9b1d6b576129
17:54:54.663 INFO - Got result: OK,286048 on session f5af93f896a24a5f893c9b1d6b576129
286048
呵呵,运行完上面程序,大概你对自动化有个初步的印象,别急,我们对上面这个程序在做修改。
首先把这个脚本类做成以testUite4方式运行的类,有些数据比较经常变动的就不要放在这个类里面,可以放在外部properties文件里。
创建一个properties文件放在Src目录下,命名为resource,内容如下:
PRODUCTID=286048
NAME= testjingdongcom
PASSWORD=jingdong
public class TestJingDongTest1 {
SeleniumServer server;
Selenium selenium;
/**
* @throws java.lang.Exception
*/
@Before
public void setUp() throws Exception {
RemoteControlConfiguration cfg = new RemoteControlConfiguration();
try {
server = new SeleniumServer(cfg);
server.boot();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// 启动Selenium
selenium = new DefaultSelenium("localhost", 4444, "*firefox D:\\Program Files\\Mozilla Firefox\\firefox.exe",
"http://www.360buy.com/");
selenium.start();
selenium.windowMaximize();
// Selenium 设定页面响应时间最大值
selenium.setTimeout("600000");
}
/**
* @throws java.lang.Exception
*/
@After
public void tearDown() throws Exception {
selenium.close();
server.stop();
}
/**
* Test method for {@link TestJingDongTest#execute()}.
* @throws InterruptedException
*/
@Test
public void testExecute() throws InterruptedException {
private static String PROPERTIES_FILE = "resource";
private static String PRODUCTID;
private static String NAME;
private static String PASSWORD;
ResourceBundle rb = ResourceBundle.getBundle(PROPERTIES_FILE);
PRODUCTID = rb.getString("PRODUCTID");
NAME = rb.getString("NAME");
PASSWORD = rb.getString("PASSOWRD");
selenium.open("http://www.360buy.com/product/"+PRODUCTID+".html");
//等待20秒等待页面加载
Thread.sleep(20000);
selenium.click("xpath=id('InitCartUrl')");
Thread.sleep(20000);
selenium.click("xpath=id('GotoShoppingCart')");
Thread.sleep(20000);
selenium.click("xpath=id('gotoOrderInfo')");
Thread.sleep(5000);
selenium.type("xpath=id('loginname')", NAME);
selenium.type("xpath=id('loginpwd')", PASSWORD);
selenium.click("xpath=id('loginsubmitframe')");
Thread.sleep(10000);
selenium.type("xpath=id('consignee_addressName')", "张俊卿");
selenium.select("xpath=id('consignee_province')", "index=2");
Thread.sleep(5000);
selenium.select("xpath=id('consignee_city')", "普陀区*");
Thread.sleep(10000);
selenium.select("xpath=id('consignee_county')", "桃浦新村*");
selenium.type("xpath=id('consignee_address')", "上海西站");
selenium.type("xpath=id('consignee_message')", "13999999999");
selenium
.click("xpath=id('part_consignee')//div[@class='footer']/input");
Thread.sleep(5000);
selenium.check("xpath=id('IdPaymentType1')");
String s = selenium
.getText("xpath=id('part_cart')//div[@class='middle']//tr[@class='align_Center']/td[1]");
System.out.println(s);
if(Integer.valueOf(s)>0){
System.out.println(" 你所订购的商品已经产生,商品号是 :"+s);
getQuery("select * from product where product id ="+s);
Date date=new Date();
SentMessageToCustomerService(s+date.toString());
}
}
public void getQuery(String sql) {
try {
Connection conn = getConnection();
if (conn != null) {
Statement statement = conn.createStatement();
ResultSet rs = statement.executeQuery(sql);
int c = rs.getMetaData().getColumnCount();
while (rs.next()) {
System.out.println("你所要的商品在数据库中已保存");
for (int i = 1; i <= c; i++) {
System.out.print(rs.getObject(i));
}
}
rs.close();
}
freeConnection(conn);
} catch (SQLException e) {
e.printStackTrace();
}
}
public void SentMessageToCustomerService(String xml) {
//add you JMS function
}
}
呵呵,这个测试的脚本是不是已经能符合网站的基本测试需求了,当你运行一下这个脚本的时候,以前需要手工测试人员手工去做的工作自动化脚本就能自行替你完成了。
当写的这种自动化的脚本多的时候,可以采用suit的方法去执行它们,当运行suit文件的时候,suit里所有指定的脚本类都能被依次执行
import org.junit.runner.RunWith;
import org.junit.runners.Suite.SuiteClasses;
@RunWith(value=org.junit.runners.Suite.class)
@SuiteClasses({
TestJingDongTest1.class
TestJingDongTest2.class
TestJingDongTest3.class
TestJingDongTest4.class
TestJingDongTest5.class
TestJingDongTest6.class
TestJingDongTest7.class
TestJingDongTest8.class
TestJingDongTest9.class
TestJingDongTest10.class
})
public class TestSuit {
}
一个简单的小自动化框架就成型了,当然,这种小框架的能力成熟度达不到检验企业大型网站的成熟度的,那么企业级自动化框架需要的是哪些东西呢。
1,脚本语言的管理,在很多企业自动化脚本都是测试人员来写,所以决定脚本语言不可能让java写,只是让他们按照你制定的语言来写,然后你的框架能把语言翻译成java类来执行。
2,测试结果既日志的显示,日志要考虑展示的方式,因为这就是测试报告,日志展示要清晰明了。
3,测试脚本的组织和管理,比如一个大型购物网站,它有几千多个case这些测试脚本怎么管理,每次运行时要运行哪些。
4.大量测试数据运行时多线程分布式处理。
在下面的章节中,我们会一步步的展示这些怎么实现的。