“天街小雨润如酥,草色遥看近却无。最是一年春好处,绝胜烟柳满皇都。”读一首古诗,心情也随之平静下来

发布新日志

  • 一个完整的maven配置selenium webdriver工程实例(七)

    2013-10-23 11:24:48

    本文是一个完整的使用maven配置的selenium webdriver工程,主要实现了自动化测试发送邮件的功能。

    第一部分:junit test

    package choose;

    import static org.junit.Assert.assertTrue;

    import org.junit.After;
    import org.junit.Before;
    import org.junit.Test;
    import org.openqa.selenium.WebDriver;

    import webdriver.CreateWebDriver;
    import webdriver.QuitWebDriver;

    public class ChooseEnterpriseTest {

    private CreateWebDriver cwd;
    private QuitWebDriver qwd;
    private WebDriver driver;
    private ChooseEnterprise choose;

    @Before
    public void setUp() throws Exception {
    cwd = new CreateWebDriver();
    qwd = new QuitWebDriver();
    driver = cwd.GetWebDriver("ie");
    choose = new ChooseEnterprise();
    }

    @Test
    public void testChoose() {
    try{
    assertTrue(choose.Choose(driver));
    }catch(Exception e){
    e.printStackTrace();
    }
    }

    @After
    public void tearDown() throws Exception {
    cwd = null;
    choose = null;
    qwd.quitWebDriver(driver);
    driver = null;
    qwd = null;
    }
    }

  • 一个完整的maven配置selenium webdriver工程实例(六)

    2013-10-23 11:23:52

    本文是一个完整的使用maven配置的selenium webdriver工程,主要实现了自动化测试发送邮件的功能。

    第一部分:参数化

    package com.cplatform.training.parameter;

    import java.io.File;
    import java.io.FileInputStream;
    import java.io.FileNotFoundException;
    import java.io.IOException;
    import java.io.InputStream;

    import jxl.Cell;
    import jxl.Sheet;
    import jxl.Workbook;
    import jxl.read.biff.BiffException;

    public class ParameterByExcel {
    //创建getParameterFromExcel方法,根据行和列获取excel中表格的内容
    public String getParameterFromExcel(File excelFile,int rowNum,int colNum) {
    //定义String对象,用于存取读取到的excel表格中的内容,便于返回
    String str="";
    //定义一个工作簿
    Workbook rwb = null;
    //定义一个Cell
    Cell cell = null;

    // 创建输入流
    try {
    InputStream stream = new FileInputStream(excelFile);
    // 获取Excel文件对象
    rwb = Workbook.getWorkbook(stream);
    // 获取文件的指定工作表 默认的第一个
    Sheet sheet = rwb.getSheet(0);
    //通过行和列定位需要读取的单元格,并且赋值给str
    cell = sheet.getCell(colNum,rowNum);
    str = cell.getContents();

    } catch (FileNotFoundException e) {
    // TODO Auto-generated catch block
    System.out.println("~~~FileNotFoundException~~~");
    }catch (BiffException e) {
    // TODO Auto-generated catch block
    System.out.println("~~~BiffException~~~");
    } catch (IOException e) {
    // TODO Auto-generated catch block
    System.out.println("~~~IOException~~~");
    }

    return str;
    }
    }

  • 一个完整的maven配置selenium webdriver工程实例(五)

    2013-10-23 11:22:55

    本文是一个完整的使用maven配置的selenium webdriver工程,主要实现了自动化测试发送邮件的功能。

    第一部分:邮件发送 mail

    package mail;

    import java.util.* ;

    import javax.mail.* ;
    import javax.mail.internet.* ;
    import javax.activation.* ;

    /******************************
    * @author qicyt1812
    * @decription 邮件发送处理程序
    * @version 1.0
    ******************************/
    public class Mail {
    //定义发件人、收件人、SMTP服务器、用户名、密码、主题、内容等
    private String displayName;
    private String[] to;
    private String from;
    private String smtpServer;
    private String username;
    private String password;
    private String subject;
    private String content;
    private boolean ifAuth; //服务器是否要身份认证
    private String filename="";
    private Vector<String> file = new Vector<String>(); //用于保存发送附件的文件名的集合


    /**
    * 设置SMTP服务器地址
    */
    public void setSmtpServer(String smtpServer){
    this.smtpServer=smtpServer;
    }

    /**
    * 设置发件人的地址
    */
    public void setFrom(String from){
    this.from=from;
    }
    /**
    * 设置显示的名称
    */
    public void setDisplayName(String displayName){
    this.displayName=displayName;
    }

    /**
    * 设置服务器是否需要身份认证
    */
    public boolean setIfAuth(boolean ifAuth){
    this.ifAuth=ifAuth;
    System.out.println("~~~"+ifAuth+"~~~"+this.ifAuth);
    return this.ifAuth;
    }

    /**
    * 设置E-mail用户名
    */
    public void setUserName(String username){
    this.username=username;
    }

    /**
    * 设置E-mail密码
    */
    public void setPassword(String password){
    this.password=password;
    }

    /**
    * 设置接收者
    */
    public void setTo(String[] to){
    this.to=to;
    }

    /**
    * 设置主题
    */
    public void setSubject(String subject){
    this.subject=subject;
    }

    /**
    * 设置主体内容
    */
    public void setContent(String content){
    this.content=content;
    }

    /**
    * 该方法用于收集附件名
    */
    public void addAttachfile(String fname){
    file.addElement(fname);
    }

    public Mail(){

    }

    /**
    * 初始化SMTP服务器地址、发送者E-mail地址、用户名、密码、接收者、主题、内容
    */
    public Mail(String smtpServer,String from,String displayName,String username,String password,String[] to,String subject,String content){
    this.smtpServer=smtpServer;
    this.from=from;
    this.displayName=displayName;
    this.ifAuth=true;
    this.username=username;
    this.password=password;
    this.to=to;
    this.subject=subject;
    this.content=content;
    }

    /**
    * 初始化SMTP服务器地址、发送者E-mail地址、接收者
    */
    public Mail(String smtpServer,String from,String displayName,String username,String password,String[] to){
    this.smtpServer=smtpServer;
    this.from=from;
    this.displayName=displayName;
    this.ifAuth=true;
    this.username=username;
    this.password=password;
    this.to=to;
    }

    /**
    * 初始化SMTP服务器地址、发送者E-mail地址、接收者、主题、内容
    */
    public Mail(String smtpServer,String from,String displayName,String[] to,String subject,String content){
    this.smtpServer=smtpServer;
    this.from=from;
    this.displayName=displayName;
    this.ifAuth=false;
    this.to=to;
    this.subject=subject;
    this.content=content;
    }

    /**
    * 初始化SMTP服务器地址、发送者E-mail地址、接收者
    */
    public Mail(String smtpServer,String from,String displayName,String[] to){
    this.smtpServer=smtpServer;
    this.from=from;
    this.displayName=displayName;
    this.ifAuth=true;
    this.to=to;
    }
    /**
    * 发送邮件
    */
    public HashMap<String, String> send(){
    HashMap<String, String> map=new HashMap<String, String>();
    map.put("state", "success");
    String message="邮件发送成功!";
    Session session=null;
    Properties props = System.getProperties();
    props.put("mail.smtp.host", smtpServer);
    if(ifAuth){ //服务器需要身份认证
    props.put("mail.smtp.auth","true");
    SmtpAuth smtpAuth=new SmtpAuth(username,password);
    session=Session.getDefaultInstance(props, smtpAuth);
    }else{
    props.put("mail.smtp.auth","false");
    session=Session.getDefaultInstance(props, null);
    }
    session.setDebug(true);
    Transport trans = null;
    try {
    Message msg = new MimeMessage(session);
    try{
    Address from_address = new InternetAddress(from, displayName);
    msg.setFrom(from_address);
    }catch(java.io.UnsupportedEncodingException e){
    e.printStackTrace();
    }
    Address[] address = null;
    if (to!=null){
    address = new InternetAddress[to.length];
    for (int i=0; i<to.length; i++){
    String s=to[i];
    address[i] = new InternetAddress(s);
    }
    }
    msg.setRecipients(Message.RecipientType.TO,address);
    msg.setSubject(subject);
    Multipart mp = new MimeMultipart();
    MimeBodyPart mbp = new MimeBodyPart();
    mbp.setContent(content.toString(), "text/html;charset=gb2312");
    mp.addBodyPart(mbp);
    if(!file.isEmpty()){//有附件
    Enumeration<String> efile=file.elements();
    while(efile.hasMoreElements()){
    mbp=new MimeBodyPart();
    filename=efile.nextElement().toString(); //选择出每一个附件名
    FileDataSource fds=new FileDataSource(filename); //得到数据源
    mbp.setDataHandler(new DataHandler(fds)); //得到附件本身并至入BodyPart
    mbp.setFileName(fds.getName()); //得到文件名同样至入BodyPart
    mp.addBodyPart(mbp);
    }
    file.removeAllElements();
    }
    msg.setContent(mp); //Multipart加入到信件
    msg.setSentDate(new Date()); //设置信件头的发送日期
    //发送信件
    msg.saveChanges();
    trans = session.getTransport("smtp");
    trans.connect(smtpServer, username, password);
    trans.sendMessage(msg, msg.getAllRecipients());
    trans.close();

    }catch(AuthenticationFailedException e){
    map.put("state", "failed");
    message="邮件发送失败!错误原因:\n"+"身份验证错误!";
    e.printStackTrace();
    }catch (MessagingException e) {
    message="邮件发送失败!错误原因:\n"+e.getMessage();
    map.put("state", "failed");
    e.printStackTrace();
    Exception ex = null;
    if ((ex = e.getNextException()) != null) {
    System.out.println(ex.toString());
    ex.printStackTrace();
    }
    }
    System.out.println("\n提示信息:"+message);
    map.put("message", message);
    return map;
    }

    }

    第二部分:SmtpAuth

    package mail;

    public class SmtpAuth extends javax.mail.Authenticator {
    private String username,password;

    public SmtpAuth(String username,String password){
    this.username = username;
    this.password = password;
    }
    @Override
    protected javax.mail.PasswordAuthentication getPasswordAuthentication() {
    return new javax.mail.PasswordAuthentication(username,password);
    }
    }

  • 一个完整的maven配置selenium webdriver工程实例(四)

    2013-10-23 11:22:24

    本文是一个完整的使用maven配置的selenium webdriver工程,主要实现了自动化测试发送邮件的功能。

    第一部分:错误处理ErrorHandle

    package errorhandle;

    import java.io.File;
    import java.io.IOException;
    import java.text.SimpleDateFormat;
    import java.util.Date;

    import mail.Mail;

    import org.apache.commons.io.FileUtils;
    import org.openqa.selenium.By;
    import org.openqa.selenium.OutputType;
    import org.openqa.selenium.TakesScreenshot;
    import org.openqa.selenium.WebDriver;

    public class ErrorHandle {

    private String subject = "";
    private String testcase = "";

    //定义变量,存储时间,用于图片的存储
    private Date date = null;
    private SimpleDateFormat sdateFormat = null;

    public ErrorHandle(){

    subject = "xx平台,用户登录选择企业,遍历测试";
    testcase = "本用例的目的:在不知道有多少企业的情况下,遍历链接测试,保证用户所属的每个企业都可以正常进入,可用于**同一类型链接是否到达正常页面<br>"+
    "本用例的主要测试点为:<br>"+
    "1.用户登录xx平台 <br>" +
    "2.进入该用户所属的每个企业<br>"+
    "3.退出登录 <br>";


    //初始时间变量,并且设置时间格式
    date = new Date();
    sdateFormat=new SimpleDateFormat("yyyyMMddhhmmssSS");
    //System.out.println(sdf.format(date.getTime()));
    }

    public boolean ErrorHandleMsg(Mail mail,WebDriver driver,String errorMsg){

    String bodyText = driver.findElement(By.cssSelector("BODY")).getText();
    if(bodyText.matches("^[\\s\\S]*HTTP 500 -内部服务器错误[\\s\\S]*$")){

    //设置邮件标题
    mail.setSubject(subject+",测试结果:FAIL-500");

    //设置邮件内容
    mail.setContent(testcase+
    "===========================================================<br>"+
    "<b><font color=\"red\">"+errorMsg+
    "<br>"+
    "页面报错500,可能服务器宕机,请检查原因,当前页面返回的url链接为:<br>"
    +driver.getCurrentUrl()+
    "<br>当前页面的内容为:<br>"+
    driver.getPageSource()+
    "</font></b>");

    try {
    File screenShotFile = ((TakesScreenshot)driver).getScreenshotAs(OutputType.FILE);
    File pic = new File(System.getProperty("user.dir")+"/screenshot/choose/500-"+sdateFormat.format(date.getTime())+".png");
    FileUtils.copyFile(screenShotFile, pic);
    mail.addAttachfile(pic.getPath());
    } catch (IOException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
    }

    //发送邮件
    mail.send();

    System.out.println("!!!errorHandle方法中页面报错500,请检查服务器!!!");

    // returnFlag = false;

    }else if(bodyText.matches("^[\\s\\S]*404[\\s\\S]*$")){
    System.out.println("errorHandle方法中出现失败,开始发送提醒邮件");
    //设置邮件标题
    mail.setSubject(subject+",测试结果:FAIL-404");

    //设置邮件内容
    mail.setContent(testcase+
    "===========================================================<br>"+
    "<b><font color=\"red\">"+errorMsg+
    "<br>"+
    "<b><font color=\"red\">页面报错404,可能页面丢失,请检查原因,当前页面返回的url链接为:<br>"
    +driver.getCurrentUrl()
    +"<br>当前页面的内容为:<br>"
    +driver.getPageSource()
    +"</font></b>");

    try {
    File screenShotFile = ((TakesScreenshot)driver).getScreenshotAs(OutputType.FILE);
    File pic = new File(System.getProperty("user.dir")+"/screenshot/choose/404-"+sdateFormat.format(date.getTime())+".png");
    FileUtils.copyFile(screenShotFile, pic);
    mail.addAttachfile(pic.getPath());
    } catch (IOException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
    }

    //发送邮件
    mail.send();

    System.out.println("!!!errorHandle方法中页面报错404,可能页面丢失,请检查原因!!!");

    }else{
    // System.out.println("errorHandle方法中页面报错404,开始发送提醒邮件");
    //设置邮件标题
    mail.setSubject(subject+",测试结果:FAIL");

    //设置邮件内容
    mail.setContent(testcase+
    "===========================================================<br>"+
    "<b><font color=\"red\">"+errorMsg+
    "<br>"+
    "<b><font color=\"red\">请检查,当前页面返回的url链接为:<br>"
    +driver.getCurrentUrl()+
    "<br>当前页面的title为:<br>"
    +driver.getTitle()+
    "<br>当前页面的内容为:<br>"
    +driver.getPageSource()+
    "</font></b>");

    try {
    File screenShotFile = ((TakesScreenshot)driver).getScreenshotAs(OutputType.FILE);
    File pic = new File(System.getProperty("user.dir")+"/screenshot/choose/others-"+sdateFormat.format(date.getTime())+".png");
    FileUtils.copyFile(screenShotFile, pic);
    mail.addAttachfile(pic.getPath());
    } catch (IOException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
    }

    //发送邮件
    mail.send();

    System.out.println("!!!errorHandle方法中出现500和404以外的问题,请检查!!!");
    }

    return false;
    }
    }

  • 一个完整的maven配置selenium webdriver工程实例(三)

    2013-10-23 11:21:29

    本文是一个完整的使用maven配置的selenium webdriver工程,主要实现了自动化测试发送邮件的功能。

    第一部分:业务处理

    package choose;

    import java.io.File;
    import java.io.IOException;
    import java.text.SimpleDateFormat;
    import java.util.Date;

    import org.apache.commons.io.FileUtils;
    import org.openqa.selenium.By;
    import org.openqa.selenium.OutputType;
    import org.openqa.selenium.TakesScreenshot;
    import org.openqa.selenium.WebDriver;

    import errorhandle.ErrorHandle;

    import mail.Mail;

    /****************************************************
    * @author qicyt1812
    * @description 遍历链接测试,可用于**同一类型链接是否到达正常页面
    * @date 2013-10-14
    ****************************************************/

    public class ChooseEnterprise
    {
    //布尔变量用于存储方法返回值
    public boolean bool = false;

    //定义邮件内容
    private String content = "";

    //定义mail对象,以便于邮件发送
    private Mail mail = null;
    File file = null;
    String[] toM =null;

    private String baseUrl = "";

    //定义错误处理对象
    private ErrorHandle error = null;

    //定义变量,存储时间,用于图片的存储
    private Date date = null;
    private SimpleDateFormat sdateFormat = null;

    public ChooseEnterprise(){
    //初始测试访问地址
    baseUrl = "http://www.csdn.net/";

    //初始错误处理程序
    error = new ErrorHandle();

    //初始化邮件内容
    content ="本用例的目的:在不知道有多少企业的情况下,遍历链接测试,保证用户所属的每个企业都可以正常进入,可用于**同一类型链接是否到达正常页面<br>"+
    "本用例的主要测试点为:<br>"+
    "1.用户登录平台 <br>" +
    "2.进入该用户所属的每个企业<br>"+
    "3.退出登录 <br>"+
    "本次测试的企业有:<br>";

    /********************************
    * 配置邮件发送的相关信息
    ********************************/

    //配置邮件发送地址,可发送多个人
    toM = new String[1];
    toM[0]="qicyt1812@csdn.net";

    mail = new Mail("smtp.csdn.net","qicyt1812@csdn.net,"xx平台自动化测试","qicyt1812","qicyt password",toM);

    //初始时间变量,并且设置时间格式
    date = new Date();
    sdateFormat=new SimpleDateFormat("yyyyMMddhhmmssSS");
    //System.out.println(sdf.format(date.getTime()));
    }

    public boolean Choose(WebDriver driver){

    int i = 1;
    int j = 1;
    String str = "";
    String strLast = "";
    String msgContent = "";

    //因为不知道需要打开的链接一共有多少个,所以使用while循环,始终给一个真值,直到条件满足跳出循环
    while(i!=0){

    driver.get(baseUrl + "zwyq/cl/login.jsp");

    try{
    /*********第1步:进入登录页面,在登录页面输入**********/
    //判断是否成功进入登录页面,如果没有则跳出循环
    if(!driver.findElement(By.cssSelector("span.fontred2")).getText().matches("^[\\s\\S]*使用xxx帐号登录[\\s\\S]*$")){
    msgContent = "第"+i+"轮测试,没有正常开启登录页面";
    bool = error.ErrorHandleMsg(mail, driver, msgContent);
    break;
    }

    //输入手机号
    driver.findElement(By.id("usersPhone")).clear();
    driver.findElement(By.id("usersPhone")).sendKeys("13770646564");

    //输入密码
    driver.findElement(By.id("usersPassword")).clear();
    driver.findElement(By.id("usersPassword")).sendKeys("123456");

    //点击登录
    driver.findElement(By.cssSelector("img")).click();

    /**********第2步:到达选择企业页面*********/
    //判断是否到达选择企业页面
    // System.out.println(i+"***"+driver.findElement(By.xpath("//h3")).getText().matches("^[\\s\\S]*选择企业[\\s\\S]*$"));
    if(!driver.findElement(By.xpath("//h3")).getText().matches("^[\\s\\S]*选择企业[\\s\\S]*$")){
    msgContent = "第"+i+"轮测试,没有到达选择企业页面";
    bool = error.ErrorHandleMsg(mail, driver, msgContent);
    System.out.println("===没有到达选择企业页面,跳出===");
    break;
    }

    //获取属性为class=qy_bg的div元素的值
    str = driver.findElement(By.xpath("(//div[@class='qy_bg'])["+i+"]")).getText();
    //获取属性为class=qy_bg的div最后一个元素的值
    strLast = driver.findElement(By.xpath("(//div[@class='qy_bg'])[last()]")).getText();

    //点击企业名称,因为存在重复的值,所以需要做一些特殊处理,这个只针对于13770646564这个账号,一般情况下不会存在相同名称的企业,所以直接用else里面的语句即可。
    if(i==2||i==7){
    driver.findElement(By.xpath("(//a[contains(text(),'"+str+"')])[2]")).click();
    }else{
    driver.findElement(By.xpath("(//a[contains(text(),'"+str+"')])")).click();
    }

    /**********第3步:进入企业内刊主页***********/
    //判断是否进入内刊主页
    if(!driver.findElement(By.xpath("//p[2]")).getText().matches("^[\\s\\S]*"+str+"[\\s\\S]*$")){
    msgContent = "第"+i+"轮测试,{"+str+"}企业,没有进入企业内刊主页";
    bool = error.ErrorHandleMsg(mail, driver, msgContent);
    break;
    }

    //如果成功进入,则截取内刊图片
    try {
    File screenShotFile = ((TakesScreenshot)driver).getScreenshotAs(OutputType.FILE);
    File pic = new File(System.getProperty("user.dir")+"/screenshot/choose/"+i+"-"+str+"-"+sdateFormat.format(date.getTime())+".png");
    FileUtils.copyFile(screenShotFile, pic);
    mail.addAttachfile(pic.getPath());
    } catch (IOException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
    }

    /**********第4步:点击进入个人中心的*************/
    //点击个人中心的图标
    driver.findElement(By.cssSelector("div.r_sz > a > img")).click();
    //检查是否了进入个人中心
    if(!driver.findElement(By.xpath("//div[4]/div[2]/h5")).getText().matches("^[\\s\\S]*退 出[\\s\\S]*$")){
    msgContent = "第"+i+"轮测试,{"+str+"}企业,没有到达个人中心页面";
    bool = error.ErrorHandleMsg(mail, driver, msgContent);
    break;
    }

    /**********第5步:退出登录**********/
    //点击退出
    driver.findElement(By.linkText("退 出")).click();
    //检查是否成功退出
    if(!driver.findElement(By.cssSelector("p.fontred")).getText().matches("^[\\s\\S]*欢迎登录xxx[\\s\\S]*$")){
    msgContent = "第"+i+"轮测试,{"+str+"}企业,退出失败,没有正常返回到登录页面";
    bool = error.ErrorHandleMsg(mail, driver, msgContent);
    break;
    }

    j = i;

    // System.out.println(j);
    System.out.println(j+"==="+str+"==="+strLast);

    content += "<b>"+i+":"+str+"<br></b>";

    //当str的值等于strLast,表示已经到达最后一个链接,此时可跳出循环
    if(strLast.equalsIgnoreCase(str)){
    mail.setSubject("xxx平台,用户登录选择企业,遍历测试:PASS");
    mail.setContent(content);
    mail.send();
    break;
    }

    i++;

    bool = true;
    }catch(Exception e){
    msgContent = "第"+i+"轮测试,捕获异常:<br>"+e.toString();
    bool = error.ErrorHandleMsg(mail, driver, msgContent);
    break;
    }

    }

    return bool;
    }
    }

  • 一个完整的maven配置selenium webdriver工程实例(二)

    2013-10-23 11:20:42

    本文是一个完整的使用maven配置的selenium webdriver工程,主要实现了自动化测试发送邮件的功能。

    第一部分:Create Webdriver

    package webdriver;
    import java.util.concurrent.TimeUnit;

    import org.openqa.selenium.WebDriver;
    import org.openqa.selenium.firefox.FirefoxDriver;
    import org.openqa.selenium.ie.InternetExplorerDriver;
    import org.openqa.selenium.remote.SessionNotFoundException;

    public class CreateWebDriver {
    private WebDriver driver;

    public WebDriver GetWebDriver(String exploreType){

    if (exploreType.equals("ie")){
    try{
    //配置IEDriverServer.exe,使用IE浏览器,必须用IEDriverServer.exe驱动
    System.setProperty("webdriver.ie.driver", "C:\\Program Files (x86)\\Internet Explorer\\IEDriverServer.exe");

    //new一个InternetExplorerDriver对象
    driver = new InternetExplorerDriver();

    //设置超时等待时间
    driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS) ;

    }catch(SessionNotFoundException se){
    System.out.println("~~4~~捕获SessionNotFoundException异常~~");
    }

    return driver;
    }else if(exploreType.equals("firefox")){

    //new一个FirefoxDriver对象
    driver=new FirefoxDriver();

    //设置超时等待时间
    driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS) ;

    return driver;
    }else{
    throw new IllegalStateException("selected explorer is not supported");
    }
    }


    }

    第二部分:Quit Webdriver

    package webdriver;

    import java.util.Set;

    import org.openqa.selenium.WebDriver;

    public class QuitWebDriver {
    public void quitWebDriver(WebDriver driver){
    Set<String> windows=driver.getWindowHandles();
    for(String a:windows){
    driver.switchTo().window(a).close();
    }
    try {
    Thread.sleep(15);
    driver.quit();
    } catch (InterruptedException ex) {
    System.out.println("~~~退出WebDriver时报InterruptedException异常~~~");
    }
    }
    }

  • 一个完整的maven配置selenium webdriver工程实例(一)

    2013-10-23 11:17:54

    本文是一个完整的使用maven配置的selenium webdriver工程,主要实现了自动化测试发送邮件的功能。

    第一部分:maven pom.xml

    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>zwyq</groupId>
    <artifactId>zwyq</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>

    <name>zwyq</name>
    <url>http://maven.apache.org</url>

    <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencies>
    <!-- 加载junit包 -->
    <dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.10</version>
    <scope>test</scope>
    </dependency>

    <!-- 加载selenium包 -->
    <dependency>
    <groupId>org.seleniumhq.selenium</groupId>
    <artifactId>selenium-java</artifactId>
    <version>2.31.0</version>
    </dependency>

    <!-- 加载javax.mail包,用于邮件发送 -->
    <dependency>
    <groupId>javax.mail</groupId>
    <artifactId>mail</artifactId>
    <version>1.5.0-b01</version>
    </dependency>

    <!-- 加载读取Excle所需的jar包 -->
    <dependency>
    <groupId>net.sourceforge.jexcelapi</groupId>
    <artifactId>jxl</artifactId>
    <version>2.6.12</version>
    </dependency>

    <!-- 加载excel读取所需的org.apache.poi包 -->
    <dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi-excelant</artifactId>
    <version>3.9</version>
    </dependency>
    </dependencies>
    < /project>

  • Selenium的演变过程

    2013-10-14 16:56:34

    本文依据selenium 官方文档,结合自己的理解完成,可能存在不尽准确的地方,各位看官请多多指教。

    2004年,Jason Huggins 在ThoughtWorks测试一个内部应用,作为一个有头脑的人,他不能局限于将有限的生命投入到无限的手工测试中去,他必须去改变这种现状,遇上他就开发了一套Javascript. library,在多个浏览器上自动运行test cases,这个Javascript. library最终变成了 selenium score,实现了Selenium Remote Control (RC) and Selenium IDE的基础功能。

    虽然selenium是一款强大的自动化工具,但是他也是有一定缺陷的,他的javascript是基于自动引擎和具有一定安全限制的浏览器上运行。更糟糕的是,webapps变得越来越强大,并且会越来越多的使用浏览器提供的一些特有特性。selenium的局限性越来越明显。

    | |

    | |

    | |

    2006年,Google一个非常勇敢的工程师Simon Stewart开始一个被叫做WebDriver的工程。Google已经使用Selenium很长时间了,但是测试人员不得不使用有局限性的产品。Simon想到了一款测试工具能够直接使用‘本土’的方法为浏览器和操作系统,以此规避这个Javascript环境带来的沙盒限制。WebDriver工程就为了这个目标而开始。

    | |

    | |

    | |

    2008年,北京奥林匹克运动会标志着中国已经达到了一个全球化的高度。这一年最重要的事情就是Selenium and WebDriver的归并。Selenium 已经有大量用户的支持,但是WebDriver才是这个工具真正的未来,两个工具的合并给用户提供了统一的特性,并且带来更多新的亮点,成功绕开了javascript. sandbox问题。

    Selenium 2 (aka. Selenium Webdriver)

    Selenium 1 (aka. Selenium RC or Remote Control)

    http://docs.seleniumhq.org/docs/01_introducing_selenium.jsp

  • Selenium WebDriver在不知道元素个数的情况下,完成页面所有元素的遍历

    2013-10-14 16:50:56

    以一个选择企业页面为例,假设事先并不知道用户登录后会有几个企业供选择,但是case又需要遍历各个企业,保证各个企业均可正常被访问,那么就可以用红色标记的方式处理。

    public class ChooseEnterprise {
    private WebDriver driver;
    private String baseUrl;
    private StringBuffer verificationErrors = new StringBuffer();

    @Before
    public void setUp() throws Exception {
    System.setProperty("webdriver.ie.driver", "C:\\Program Files (x86)\\Internet Explorer\\IEDriverServer.exe");
    driver = new InternetExplorerDriver();
    baseUrl = "http://xx.xxx.cn/";
    driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);
    }

    @Test
    public void testChooseEnterprise() throws Exception {

    int i = 1;
    int j = 1;
    String str = "";
    String strLast = "";

    //因为不知道需要打开的链接一共有多少个,所以使用while循环,始终给一个真值,直到条件满足跳出循环
    while(i!=0){


    driver.get(baseUrl + "xx/xx/login.jsp");

    //判断是否成功进入登录页面
    try {
    assertEquals("使用手机帐号登录", driver.findElement(By.cssSelector("span.fontred2")).getText());
    } catch (Error e) {
    verificationErrors.append(e.toString());
    }

    driver.findElement(By.id("usersPhone")).clear();
    driver.findElement(By.id("usersPhone")).sendKeys("13800000000");

    driver.findElement(By.id("usersPassword")).clear();
    driver.findElement(By.id("usersPassword")).sendKeys("123456");

    driver.findElement(By.cssSelector("img")).click();

    //判断是否到达选择企业页面
    try {
    assertEquals("选择企业", driver.findElement(By.xpath("//h3")).getText());
    } catch (Error e) {
    verificationErrors.append(e.toString());
    }

    //获取属性为class=qy_bg的div元素的值

    str = driver.findElement(By.xpath("(//div[@class='qy_bg'])["+i+"]")).getText();

    //获取属性为class=qy_bg的div最后一个元素的值
    strLast = driver.findElement(By.xpath("(//div[@class='qy_bg'])[last()]")).getText();

    driver.findElement(By.xpath("(//a[contains(text(),'"+str+"')])")).click();



    //判断是否进入各企业主页
    try {
    assertEquals(str, driver.findElement(By.xpath("//p[2]")).getText());
    } catch (Error e) {
    verificationErrors.append(e.toString());
    }

    //点击进入个人中心的图标,进行退出操作
    driver.findElement(By.cssSelector("div.r_sz > a > img")).click();
    //检查是否了进入个人中心
    try {
    assertEquals("个人中心", driver.getTitle());
    } catch (Error e) {
    verificationErrors.append(e.toString());
    }
    //点击退出
    driver.findElement(By.linkText("退 出")).click();
    //检查是否成功退出
    try {
    assertEquals("欢迎登录网信", driver.findElement(By.cssSelector("p.fontred")).getText());
    } catch (Error e) {
    verificationErrors.append(e.toString());
    }

    //j可以统计出一共有多少个企业,供测试结果输出使用
    j = i;

    System.out.println(j);
    System.out.println(str);

    //当str的值等于strLast,表示已经到达最后一个链接,此时可跳出循环
    if(strLast.equalsIgnoreCase(str)){
    break;
    }


    i++;
    }

    }

    @After
    public void tearDown() throws Exception {
    driver.quit();
    }
    }

  • 在Selenium WebDriver中使用By.Xpath快速定位页面元素

    2013-07-17 15:04:28



    以登录页面密码框定位为例,讲解如何在selenium webdriver中通过by.xpath定位页面元素,快速获取元素位置并完成操作。

     

    问题引入:

     

    Selenium IDE录制后的脚本如下:

    driver.findElement(By.name("pass")).clear();

    driver.findElement(By.name("pass")).sendKeys(" ");

    driver.findElement(By.id("passwords")).clear();

    driver.findElement(By.id("passwords")).sendKeys("123456");

    回放的时候,页面非常难定位,需要很长时间才能找到密码框并输入密码,如果超时了找不到就会报错。

     

    解决方案:

    既然有时候能回放成功,有时候又找不到页面元素,那肯定是这个元素定位不够准确,所以在查找的时候会消耗很长时间,那么通过xpah定位是否可以?

     

    Xpath查找元素对象时有这样一种定位方式,即通过//定位,详情请参考:http://www.w3school.com.cn/xpath/xpath_syntax.asp

    //

    从匹配选择的当前节点选择文档中的节点,而不考虑它们的位置。

    比如这里密码框是输入框input,想要查找input的位置可以通过//input来实现,如果只是//input则可能会定位到多个input元素,此时就需要通过键值对更精确的定位,语法就是//input[@key=value],即://input[@name='pass']

     

    driver.findElement(By.xpath("//input[@name='pass']")).clear();

    driver.findElement(By.xpath("//input[@name='pass']")).sendKeys(" ");

    driver.findElement(By.xpath("//input[@id= passwords]")).clear();

    driver.findElement(By.xpath("//input[@id= passwords]")).sendKeys("123456");

    重新回放,时间仍然很长,看来通过一个元素键值对定位是不可靠的,那能不能通过多个元素呢?就跟QTP中的高级描述性编程一样。那xpath的语法是什么,多个元素键值对怎么连接到一起呢?

     

    首先查找name=pass的这个元素的另外一个元素键值对:class= textfild,用这两个定位一下试试看。

    driver.findElement(By.xpath("//input[@name='pass' and @class=’ textfild’]")).clear();

    driver.findElement(By.xpath("//input[@name='pass' and @class=’ textfild’]")).sendKeys(" ");

    driver.findElement(By.xpath("//input[@id= passwords and @class=’ textfild required’]")).clear();

    driver.findElement(By.xpath("//input[@id=passwords and @class=’textfild required’]")).sendKes(“12..”);

    再回访,速度果然快了,很快便识别到了密码框的位置,并且进行了输入。

     

    关于xpath 查找元素还可以通过contains一个字符串查找函数)来实现,语法是

    //input[contains(@id,vakue) and contains(@id,value)],此中的idvalue就是定位input元素的键值对

     

    例如:

    //input[contains(@class,'textfild') and contains(@name,'pass')]

     

    那最后经过整合和简化,4句的代码可简化为以下两句

    driver.findElement(By.xpath("//input[contains(@class,'textfild') and contains(@name,'pass')]")).clear();

    driver.findElement(By.xpath("//input[@id='passwords' and @class='textfild required' and @type='password']")).sendKeys("123456");

     

    为什么能简化为2行呢,看上面的截图,其实一上来的时候密码框里有“密码”两个字,当鼠标移入密码框获取焦点以后,“密码”文字消失,用户就可以输入自己真正的密码。所以

    driver.findElement(By.xpath("//input[@name='pass' and @class=’ textfild’]")).sendKeys(" ");

    这句话是我们不需要的。因为当密码框获取焦点以后,“密码”文字就消失了,所以下面的清空也没有必要存在了

    driver.findElement(By.xpath("//input[@id= passwords and @class=’ textfild required’]")).clear();

    这样,代码就简化了。

    回放,一切ok

  • Maven+Eclipse+Tomcat配置详解(二)

    2013-03-13 11:58:12

    <!--[if !supportLists]-->1.       <!--[endif]-->MyEclipse中配置tomcat注意:tomcat server必须选择为Enable,否则不可用

    <!--[if !vml]--><!--[endif]-->(图19

     

    ------------------------------------------------------------4.示例------------------------------------------------------------

     

    <!--[if !supportLists]-->1.       <!--[endif]-->现在就使用上面的配置创建我们的第一个maven webapp工程吧,打开MyEclipseFile->New->Others->Maven->Maven Project

    <!--[if !vml]--><!--[endif]-->(图20

    <!--[if !vml]--><!--[endif]-->(图21

    CatalogAll Catalogsmabaen-archetype-webapp

    <!--[if !vml]--><!--[endif]-->(图22

    Group Id Artifact IdVersion都是Maven的几个关键元素,这三个元素定义了项目的基本坐标,Maven的世界,任何的jarpom或者war都是以基于这些基本的坐标进行区分的

     

    groupId定义了项目属于哪个组(可以理解为项目的package),artifactId定义了当前Maven项目在组中唯一的ID可以理解为项目名称),version指定了项目当前的版本。

     

    <!--[if !vml]--><!--[endif]-->(图23

    <!--[if !supportLists]-->2.       <!--[endif]-->了解MyEclipse中项目的结构,web项目必须在src\main\webapps下面才可以成功编译和部署。

    <!--[if !vml]--><!--[endif]-->(图24

    <!--[if !supportLists]-->3.       <!--[endif]-->修改index文件,做一个简单的标示。成功运行项目后,页面将显示为如下信息

    <!--[if !vml]--><!--[endif]-->(图25

    <!--[if !supportLists]-->4.       <!--[endif]-->pom.xml文件是maven的核心(pomProject Object Model),在该文件中可以加载任何项目所需的插件,系统会自动将这些项目所需的插件从maven repository center下载下来。因为要希望把项目部署到外部tomcat下面,所以此处需要加入tomcat-maven插件,以及希望启动的tomcat配置

             <plugins>

            <plugin>

                <groupId>org.apache.tomcat.maven</groupId>

                <artifactId>tomcat6-maven-plugin</artifactId>

                <version>2.0-beta-1</version>

               <configuration>

                  <url>http://localhost:6080/manager</url>

                  <server>tomcat6</server>

                  <port>6080</port>

                  <path>/MyFirstMaven</path>

               </configuration>

           </plugin>

       </plugins> <!--[if !vml]--><!--[endif]-->(图26

     

    <!--[if !supportLists]-->5.       <!--[endif]-->运行工程,选择工程名邮件Run As->maven clean,会将之前编译的内容清除重新编译。

    <!--[if !vml]--><!--[endif]-->(图27

    然后执行maven bulid,并在goals中输入package tomcat6:deploy

    <!--[if !vml]--><!--[endif]-->(图28

    先查看一下(图28run之前tomcat\webapps目录下的内容

    <!--[if !vml]--><!--[endif]-->(图29

    Run(图28),当MyEclipse中的console控制台输出的内容为BUILD SUCCESS时,就表示部署成功了

    <!--[if !vml]--><!--[endif]-->(图30

    (图28Run之后tomcat\webapps目录下的内容,多了MyFirstMavenMyFirstMaven.war两个文件,表示项目发布成功

    <!--[if !vml]--><!--[endif]-->(图31

     

    MyEclipse->项目右键->Run As->Maven Build,输入tomcat6:run,就可启动tomcat

    <!--[if !vml]--><!--[endif]-->(图32

    出现如下信息表示tomcat启动成功

    <!--[if !vml]--><!--[endif]-->(图33

    在浏览器中输入http://localhost:6080/MyFirstMaven并访问

    <!--[if !vml]--><!--[endif]-->(图34

    Okmaven webapp项目实例完成。

     

     

    ------------------------------------------------5.问题解答--------------------------------------------------------

     

    maven build工程的时候,大多数资料都是显示tomcat:deploy等等,于是一开始也是按照tomcat:deploy格式输入的,结果会产生大量的报错,而且启动的tomcat端口是8080,是eclipse自带的tomcat,而不是我们设置的6080端口的tomcat。错误信息如下:

    [DEBUG]   (f) charset = ISO-8859-1

    [DEBUG]   (f) contextFile = D:\eclipse\workspaces\MyFirstMaven\target\MyFirstMaven\META-INF\context.xml

    [DEBUG]   (f) ignorePackaging = false

    [DEBUG]   (f) mode = war

    [DEBUG]   (f) packaging = war

    [DEBUG]   (f) path = /MyFirstMaven

    [DEBUG]   (f) update = false

    [DEBUG]   (f) url = http://localhost:8080/manager

    [DEBUG]   (f) version = 1.1

    [DEBUG]   (f) warFile = D:\eclipse\workspaces\MyFirstMaven\target\MyFirstMaven.war

    [DEBUG] -- end configuration --

    [INFO] Deploying war to http://localhost:8080/MyFirstMaven 

    [DEBUG] No server specified for authentication - using defaults

    [INFO] ------------------------------------------------------------------------

    [INFO] BUILD FAILURE

    [INFO] ------------------------------------------------------------------------

    [INFO] Total time: 2.797s

    [INFO] Finished at: Wed Mar 13 11:24:37 CST 2013

    [INFO] Final Memory: 6M/12M

    [INFO] ------------------------------------------------------------------------

    [ERROR] Failed to execute goal org.codehaus.mojo:tomcat-maven-plugin:1.1:deploy (default-cli) on project MyFirstMaven: Cannot invoke Tomcat manager: Server returned HTTP response code: 400 for URL: http://localhost:8080/manager/deploy?path=%2FMyFirstMaven&war= -> [Help 1]

    org.apache.maven.lifecycle.LifecycleExecutionException: Failed to execute goal org.codehaus.mojo:tomcat-maven-plugin:1.1:deploy (default-cli) on project MyFirstMaven: Cannot invoke Tomcat manager

        at org.apache.maven.lifecycle.internal.MojoExecutor.execute

  • Maven+Eclipse+Tomcat配置详解(一)

    2013-03-13 11:52:53

    Maven+Eclipse+Tomcat配置详解

     

    前言:本文介绍的内容都是基于JDK配置ok的情况下进行的,JDK的配置在此不做描述。

     

    ------------------------------------------------1.Maven的配置--------------------------------------------------------

     

    1.       下载maven,此处使用apache-maven-3.0.5版本,下载地址:

    http://maven.apache.org/docs/3.0.5/release-notes.html

    2.       解压apache-maven-3.0.5D:\eclipse\

    (图1

    3.       拷贝apache-maven-3.0.5/conf/settings.xml

    C:\Documents and Settings\Administrator\.m2

    (图2

     

    说明:如果setting.xml放置到maven/conf下面相当于全局变量,其修改会影响所有使用maven的人,放置到Administrator\.m2下面是针对某个用户Administrator而言,起修改仅会影响到该用户

    4.       修改C:\Documents and Settings\Administrator\.m2\settings.xml

    (1)     修改maven本地资源库的配置,以后maven用到的所有资源文件都会存储到该目录下:

    <localRepository>D:\eclipse\apache-maven-local-repository</localRepository>

    (图3

    (图4

    (2)     再说一说settings.xml 文件中与tomcat相关的配置,以备后面集成使用,此步骤可暂缓进行,此处只是为了文档完整性而作。<id>标签可以理解为tomcat别名,比如本人使用的是apache-tomcat-6.0.36,那<id>标签中的内容为tomcat6记住这个别名,很重要的,后面的pom.xml配置,以及eclipsemaven build中都会用到),<username><password>标签内容对应apache-tomcat-6.0.36\conf\tomcat-users.xml中设置的用户名和密码。(此步骤可在配置完tomcat以后再配置

    <server>

          <id>tomcat6</id>

          <username>admin</username>

          <password>admin</password>

        </server>(图5

    5.           配置环境变量MAVEN_HOME MAVEN_HOME=D:\eclipse\apache-maven-3.0.5注意,路径最后不要加\,如果加了\,那后面path读出来的变量名称就是D:\eclipse\apache-maven-3.0.5\\bin,显然是错误的

    (图6

    6.       配置环境变量path:在path里面添加%MAVEN_HOME%\bin; 注意,英文状态下的分号;不能少

    (图7

    环境变量配置好以后,在cmd里输入mvn –version,如果出现下图信息,表示配置成功。

    (图8

     

    至此,maven的配置完成。

     

    ------------------------------------------------2.Tomcat的配置--------------------------------------------------------

     

    1.       下载tomcat,可到apache官网http://tomcat.apache.org/download-60.cgi

    2.       解压apache-tomcat-6.0.36D:\eclipse\

    (图9

    3.       修改tomcat的配置D:\eclipse\apache-tomcat-6.0.36\conf,首先修改server.xmltomcat默认端口是8080,为防止端口冲突,将8080修改为6080

    <Connector port="6080" protocol="HTTP/1.1"

                   connectionTimeout="20000"

                   redirectPort="8443" />

    (图10

    4.       然后修改D:\eclipse\apache-tomcat-6.0.36\conf\tomcat-users.xml,为tomcat配置管理员账号

    <user username="admin" password="admin" roles="manager"/>

    (图11

    5.       修改完tomcat的配置后进入D:\eclipse\apache-tomcat-6.0.36\binstartup.bat启动tomcat,在地址栏里输入:http://localhost:6080/manager/html,弹出用户名和密码输入框,输入第4步骤设置的用户名和密码。

    (图12

    登录成功后进入tomcat管理页面,表示tomcat配置成功

    (图13

    至此,tomat配置完成。

    ------------------------------------------------3.Eclipse的配置--------------------------------------------------------

     

    1.       安装EclipseMyEclipse,可到官网下载

    (图14

    2.       启动MyEclipse,进入help->MyEclipse Configuration Center

    (图15

    3.       进入Center中心后切换到SoftWare标签,一般高版本的MyEclipse会自带Maven插件,可先通过My SoftWare中卸载Maven插件,然后再在Browser SoftWare中通过add site添加m2eclipse

    Mavenhttp://download.eclipse.org/technology/m2e/releases

    最后通过Pending Changes中的【Apply 1 change 】安装插件,中间可能会需要多次重启MyEclipse

    (图16

    4.       MyEclipseMaven插件安装完成后,在window->preference中会看到Maven插件,然后就是对Maven进行配置,首先是Installations,需要将本地的Maven添加进来D:\eclipse\apache-maven-3.0.5,并且配置好Global Setting

    (图17

    然后再配置User Settings

    (图18


  • svn在windows系统中的安装与配置

    2010-10-25 17:18:01

    1.  软件下载

    (1)   svn服务器:   svn-1.4.5-setup.rar

    http://www.cnblogs.com/Files/changchangcc520/svn-1.4.5-setup.rar

    (2)   svn客户端: TortoiseSVN-1.4.5.10425-win32-svn-1.4.5.rar

    http://www.cnblogs.com/Files/cha ... win32-svn-1.4.5.rar

    (3)   配置svn服务成window service自动运行的工具: SVNService.rar

    http://www.cnblogs.com/Files/changchangcc520/SVNService.rar



    http://dark.clansoft.dk/~mbn/svnservice/ 下载 SVNService.zip

     

    (说明:Svn客户端和服务器端直接解压按正常步骤安装即可,对于配置svn服务撑windows服务需要做配置,详见操作3)

     
    2.  创建项目资源库

    创建一个存放项目的资源库目录D:\SVNRoot\Repository\Project

    svnadmin create D:\SVNRoot\Repository\Project

    3.  配置svn服务器为windows服务

    (1)   将SVNService.rar 解压到{Subversion安装路径的}\bin目录下

    (2)   运行 svnservice -install -d -r D:\SVNRoot\Repository\Project,执行的结果显示:SVNService installed.

    (3)   使用net start SVNService启动SVNService服务

    注册完成后会在window的服务中看到SVNService服务

    或者,如果你不想用服务的方式启动Subversion,你可以运行svnserve -d来启动Subversion

    4.  修改配置文件

    在..\project\conf文件夹下有:svnserver.conf,passwd,author三个文件

     

    Passwd修改:

    ***********************************************

    ### This file is an example password file for svnserve.

    ### Its format is similar to that of svnserve.conf. As shown in the

    ### example below it contains one section labelled [users].

    ### The name and password for each user follow, one account per line.

    ### 增加两个用户,格式为  “用户名 = 密码”

    [users]

    admin = manager        

    sunny = manager

    **********************************************

     

    Svnser.conf修改

    *********************************************

         [general]

    anon-access = read    #未验证用户给予只读权限

    auth-access = write   #验证用户给予写权限

    password-db = passwd  #密码存放到passwd文件中

    realm = project       #创建的项目标识

    *****************************************

     

    Author修改

    ************************************************

    [groups]
    # harry_and_sally = harry,sally
    #进行用户组的配制,比如:将admin,sunny加入到组groups中去 

    groups=admin,sunny

     

    # [repository:/baz/fuz]
    # @harry_and_sally = rw
    # * = r

     

    ###进行文件权限的设置,比如存在libs这个文件,要求admin一个人可以读写,sunny有读权限,未授权的无法访问,则可以这样写

     

    [/libs]
    admin=rw
    lvzy=r
    *=none
    注:*表示匿名用户

    *******************************

     
    5.  使用cmd命令进行svn操作

    (1) 导入项目

    转到项目所在的目录,执行下面命令来提交整个项目
    svn import .svn://localhost/project -m "initial import" --username sunny --password manager
    其中[.]表示当前目录,你也可以指定项目的绝对路径。

     

    (2) 导出项目

    为了验证刚才导入的项目,我们转到一个新的目录下,执行
    svn checkout svn://localhost/project --username sunny -password manager
    就可以在当前目录下生成一个project的项目目录,目录中的内容就是我们刚才所提交的所有文件

     

    (3)  提交修改后的文件

    修改项目中的任何一个文件,使用命令来提交所作的修改:
    svn commit ReadMe.txt -m "modified" --username sunny -password manager

     

    (4) 获取最新的版本

    当项目组的其他成员修改并提交了某个文件,你可以通过下面命令来获取到该文件的最新的版本:
    svn update -r HEAD ReadMe.txt --username sunny -password manager
    6.  在Eclipse中对项目进行版本控制

    (1)   安装subversion插件

    首先通过Help->Check for Updates查看Eclipse是否需要更新,然后通过Install New SoftWare在线更新安装subversion

    选择http://subclipse.tigris.org/servlets/ProjectProcess?pageID=p4wYuA页面进行在线更新:Eclipse update site URL:

    http://subclipse.tigris.org/update_1.6.x

    安装完成后在Window->Preferences->Team->SVN,默认设置即可

    (2)   创建Java工程,在工程右键属性Team选项

    加入版本控制的程序如图:

    7.  使用TortoiseSVN进行管理

    在任意文件夹下面右键选择Reop-Browser,输入svn://svn_server_ip/即可查看

  • 使用LoadRunner Java Vuser协议连接Oracle数据库并执行查询

    2010-07-30 13:09:17

     

    1、 不要使用System等系统用户连接ODBCOracle不支持

    2、 创建Oracle新用户并赋予权限:

    Create User lruser Identified by lrpassword;

     

    GRANT CREATE USER,DROP USER,ALTER USER ,CREATE ANY VIEW ,

       DROP ANY VIEW,EXP_FULL_DATABASE,IMP_FULL_DATABASE,

      DBA,CONNECT,RESOURCE,CREATE SESSION TO lruser;

     

    3、 创建表并插入数据:

    create table students(

      stuNo VARCHAR2(256) not null,

      stuName VARCHAR2(256),

      stuSex  VARCHAR2(10)

    );

     

    alter table students add constraint stuNo_PK primary key (stuNo) using index;

     

     

    select * from students;

     

    insert into students values('001','susan','girl');

    insert into students values('002','Tom','boy');

    insert into students values('003','Jessica','girl');

    insert into students values('004','Marry','girl');

    insert into students values('005','Shine','girl');

    insert into students values('006','Lucky','boy');

    insert into students values('007','Peter','boy');

    insert into students values('008','Sue','boy');

    insert into students values('009','Kiss','girl');

    insert into students values('010','Pop','boy');

     

    4、 创建数据源

    管理工具 - > 数据源,创建数据源,步骤5中的 

    String dbUrl = "jdbc:odbc:Oracle_ODBC"; 其中Oracle_ODBC就是创建的本地数据源

     

    5、 LoadRuner Vugen中选择Java Vuser协议,创建脚本:

    import java.io.*;

    import lrapi.lr;

    import java.sql.*;

     

    public class Actions

    {

        int sum=0;

     

        public int init() throws Throwable {

     

           return 0;

     

        }//end of init

     

        public int action() throws Throwable {

               try{

                      //定义了数据库连接串

                      String dbUrl = "jdbc:odbc:Oracle_ODBC";

                      //数据库的用户名

                      String user = "lruser";

                      //数据库的用户口令

                      String password = "lrpassword";

                      // 加载jdbc-odbc bridge驱动程序

                      Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");

     

                      // url指定的数据源建立连接

                      Connection conn = DriverManager.getConnection(dbUrl, user, password);

                 

                      //采用Statement进行查询

     

                         //插入LoadRunner的事务lr_select_data_trans

                      lr.start_transaction("lr_select_data_trans");

          

                      Statement stat = conn.createStatement();

                      ResultSet rs = stat.executeQuery("SELECT stuNo,stuName,stuSex FROM students;");

     

          

                      lr.message("\t"+"stuNo"+"\t"+"stuName"+"\t"+"stuSex"+"\n");

                      //函数输出表的各个字段名字

                      while(rs.next())

                      {

                         lr.message("\t"+rs.getString(1)

                                  +"\t"+rs.getString(2)

                                  +"\t"+rs.getString(3)

                                  +"\n");

     

                         sum=sum+1;

                      }

                      rs.close();

                      stat.close();

                      conn.close();

     

     

               lr.message("Sum="+sum);

     

                  // lr_select_data_trans事务结束

               lr.end_transaction("lr_select_data_trans ",lr.AUTO);

     

               }catch(Exception e){

                      e.printStackTrace();

     

                      System.out.println("Test Failed");

               }

     

          

               return 0;

           }//end of action

     

        public int end() throws Throwable {

           return 0;

        }//end of end

    }

    6、 执行脚本

  • 关于测试用例的探讨(讨论稿)

    2010-06-22 14:31:10

    测试用例是测试过程中不可或缺的部分,如何形成一种合理的工作流程,设计出高效的测试用例,用例应该遵循什么样的书写规范,这是对整个项目质量提高的一种保证,也是对我们测试人员自身用例设计能力的一种提高。本文初步整理了一些测试用例的设计规范,希望能够抛砖引玉,多多收获大家的意见或建议。

    测试用例的六大特性

    1. 测试用例对需求覆盖的完整性

    测试是基于需求的,所以说测试用例应该尽可能100%的覆盖需求。100%的覆盖跟0缺陷的要求有些类似了,实现起来是非常非常困难的,但是我们应该做到尽可能的去覆盖,至少显性的需求必须保证有用例覆盖,隐性的需求可允许有一定遗漏,一旦发现遗漏后需要及时的对测试用例进行补充。

     

    2. 测试用例的有效性

    如何定义用例的有效性,什么是有效的用例,个人认为可归结为两类,一类是能发现问题,特别是严重问题,甚至是致命问题的用例,这类用例可以称之为高效用例,另一类是覆盖了需求所要求功能的用例,这类用例不一定能发现问题,但是必不可少的。

     

    3. 测试用例的易理解性

    测试用例应该是易于理解的,主要表现在语言组织方面,不使用生涩词汇,不让人产生歧义。目前我们期望的最理想的状态就是,任何一个用户,在不熟悉系统,不了解需求的情况下,拿到这个用例就可以根据步骤一步一步执行。

     

    4. 测试用例的清晰性

    测试用例的清晰性包括测试用例分类明确、设计思路清晰、操作步骤简洁明了等等。

     

    5. 测试用例的可复用性和可维护性

    之所以花很大的代价去设计测试用例就是为了能够重复使用,但是用例又不可能是一成不变的,随着产品的升级或需求的变化,用例也需要做相应的维护,如果用例设计的比较混乱,维护成本就会非常高。如何降低维护成本,提高用例的可维护性,最重要的就是需要我们设计用例时能遵循统一的规范,这样不论将来谁来维护,都可以比较容易的去进行。这一点也避免了人员流动后造成用例无法重用的尴尬局面。

     

    测试用例的生命周期

    测试用例从开始规划到设计完成直至被执行是需要一个过程的,在这里我称之为测试用例的生命周期,其实最主要的还是一个流程问题。

     

    1. 版本确定下来,需求完成并收到评审邮件时,就分配专门的测试人员熟悉需求并为用例设计做准备

     

    2. 根据产品需求或开发需求提取测试需求点,保证测试用例对需求的覆盖

    在我们开始接触需求并了解需求的时候,就可以适当的提取出测试需求点,这个需求点可以是非常详细的,也可以是比较粗略的,可以是一个测试需求对应一个测试用例,也可以是一个需求对应多个测试用例,用例设计的时候再对测试需求进行分解。

    提取测试需求的目的有二,一是帮助测试人员更快更好的理解需求,把问题发现在需求阶段,降低整个项目成本。二是对用例设计起到一定的指导作用。

    测试需求提取后记录到QC的{需求}模块中,还是记录到Excel中,这个大家可以讨论。

      

    3. 需求评审后及时对测试需求进行调整

        需求评审后,肯定会或多或少的有些变动,这个时候需要对变更后的测试需求及时做调整。此类情况是针对产品需求进行的测试需求提取,如果针对开发需求,变化的可能性会小一些。

    4. 根据测试需求设计测试用例,并且测试用例要覆盖到每个测试需求

        可直接在QC中覆盖

    5. 用例完成后提前1-2天发给相关人员阅读并发评审通知

    6. 用例评审结束后,需要对有问题的用例及时调整,调整后的用例可单独导出来,邮件给所有相关评审人员再次确认

    7. 将用例拖入执行计划,准备用例执行,执行可分两种情况,自己设计自己执行,或者交换执行,对于有条件的项目最好是交换执行。

    可直接在QC中进行

    用例执行过程中,如发现BUG,请及时将BUG ID更新到相应的用例中

    8. 执行过程中发现用例遗漏,需及时补充,如无遗漏,用例执行通过,整个生命周期结束。

     

    测试用例设计规范

    测试用例的组织结构

    测试用例首先需要清晰的表达出我们的测试思路,拿到一个需求后,应该先测什么,再测试什么,最后测试什么。

     

    如何保证测试用例的清晰性,可以先从测试用例的组织结构入手,结合之前用例设计思路,加上在网上参考的一些资料,目前测试用例可分以下几类进行设计,这几个分类在QC中表现形式为5个文件夹。

     

    功能

    该文件夹中主要包含一些的功能性的用例,可以包含正常流或异常流,以登录为列:

    正常流:用户名和密码正确,登录成功

    异常流:用户名和密码均为空,登录失败

            用户名或密码有一个为空,登录失败

                  ……

    业务逻辑与规则

        该文件夹主要包含一些业务逻辑和规则,跟具体的业务相关的用例,比如说系统允许用户名50个字符以内,采用及时校验机制。用例设计为:

       用户名正好为50个字符,离开焦点,验证通过

    用户名为中文,离开焦点,验证失败

    ……

    接口

        该文件夹主要包含一些接口相关的用例,特别是遇到系统间相互调用、模块间相互调用,与数据库的接口。比如说领动与OSS订单的接口,爱聘才与OSS编辑系统的接口,TMMIC VO的接口等等。

        以近期TM项目与MIC VO的一个举例,MIC VO中修改了用户基本信息,在TM的个人设置页面显示。

    设计该类用例时,需要有清晰的操作步骤,如果用户对系统不舒适,需要在明确说明

    操作步骤:

    (1)       TM账号登录MIC VO

    (2)       修改个人信息

    (3)       用该账号重新登录TM客户端

    (4)       点击TM头像旁边的个人设置,检查信息是否变化

    期望结果:

    TM个人设置中的信息与用户在VO中修改的个人信息一致

       

    接口用例中请注意对数据库表的检查

    页面

        该文件夹主要包含一些与页面相关的用例,如果页面元素检查、有特殊要求的页面检查

    权限

        该文件夹主要包含一些与权限有关的用例,比如说XXX网站只允许高级会员使用统计功能,用例设计为:

    用高级会员登录,有【统计】功能

    用非高级会员登录,没有【统计】功能

    控件

        该文件夹主要包含一些特殊控件的用例,比如说日历控件、分页按钮等等,因为这些控件基本上都统一调用的,我们可以作为公共用例来设计

    测试用例的设计要素

    目前测试用例的设计主要是在QC中进行,用例的要素包括:用例概述、用例优先级、前置条件、操作步骤、测试数据、预期结果、备注、对应JIRA_BUG_ID

    测试用例的书写规范

        测试用例最好能够做到尽量详细,我们的要求是尽量保证一个用例只有一个主要结果,可以包含其他辅助结果,也就是主结果完成后出现的其他现象,没有必要另建一个测试用例的,比如说xxx模块添加用户成功(主结果),系统自动跳转到用户列表页面(辅助结果)。

       

        关于用例设计要素的书写规范,我做了如下描述:

     

        用例概述(必需项):QC中表现为一个Test Case的名称,要简明扼要对该用例设计的目的进行描述。

     

        用例优先级(必需项):一些功能性的、流程性、业务规则的、接口的用例优先级最高,必须执行,一些页面的用例优先级会相对较低,可选择执行,优先级别需要视需求而定。优先级必须定义,这对建立测试执行计划有很大的帮助

     

        前置条件(可选项):对于当前的用例,必须要满足一个前提条件才能完成,这些条件如果写在操作步骤中就会很繁琐,就可以单独放置在前置条件中。前置条件可以是一个说明,一个注意事项,也可以是一个前面的case,具体视情况而定。

     

        操作步骤(必需项):尽量详细,步骤鲜明,语言简洁,为清晰的描述最终结果,操作步骤中可适当包含一些中间结果。

     

        测试数据(必需项):基本上每个测试用例都是需要有测试数据支持的,该项必不可少,有的时候可能是多种情况的测试数据对应同一个结果,这就需要每种情况准备一组数据。比如说,用户年龄范围必需为【18-25】岁之间,才可以注册XXX游戏,若满足【18-25】这个区间范围,我们可以用三个数据,18岁、20岁、25岁,这三个数据时都必须要验证的。

     

        如果不能给出明确的测试数据,可以提供测试数据准备条件,准备了几组数据,就相当于要执行这个Test case几次。

     

        预期结果(必需项):准确描述出用例的结果,结果具有唯一性。

       

        备注(可选项):一些特殊的说明地方

     

        BUG_ID(如果该用例有对应的BUG,此项必填):这个主要用于测试用例执行过程中,尽量不要怕麻烦,每发现一个BUG就要把BUG_ID记录到这个用例中,一来可以我们的BUG_ID和测试用例连接起来,二来便于对用例的有效性作统计。

     

  • Linux下为MySQL配置添加新用户

    2009-07-31 12:23:41

    为安全起见,通常是不允许直接使用root用户登录,除非你是管理员,所以此处就进Linux下为MySQL配置添加新用户的步骤进行了说明:

    1)以root用户登录
    #mysql -u root -p

    2)插入新用户,host:localhost;user:mysql;pssword:mysql
    mysql>insert into mysql.user (host,user,password) values('localhost','mysql',PASSWORD('mysql'));

    3)更新密码
    mysql>update user set password=password('mysql') where user='mysql'

    4)授予权限
    mysql>grant all privileges on *.* to mysql@'localhost' identified by 'mysql';

    其中*.*表示:数据库名.表名;

    5)刷新权限
    mysql>flush privileges;

  • Linux下mysql的安装与配置

    2009-07-29 20:08:45

    1、下载mysql文件,本文下载的是免安装文件:mysql-5.0.83-linux-i686-glibc23.tar.gz

    2、登录Linux,复制文件到/user/local/下
    [root@test ~]# cp /tools/mysql-5.0.83-linux-i686-glibc23.tar.gz /usr/local/
    [root@test ~]# cd /usr/local
    [root@test local]# ll
    total 120904
    -rwxr-Sr-t 1 root root 123603074 Jul 29 18:57 mysql-5.0.83-linux-i686-glibc23.tar.gz

    3、因为上面的文件带有一个复位S权限,所以使用chmod变更文件权限
    [root@test local]# chmod 755 mysql-5.0.83-linux-i686-glibc23.tar.gz
    [root@test local]# ll
    total 120904
    -rwxr-xr-x 1 root root 123603074 Jul 29 18:57 mysql-5.0.83-linux-i686-glibc23.tar.gz

    4、解压该tar.gz文件
    [root@test local]# tar zvxf mysql-5.0.83-linux-i686-glibc23.tar.gz
    mysql-5.0.83-linux-i686-glibc23/
    mysql-5.0.83-linux-i686-glibc23/bin/
    mysql-5.0.83-linux-i686-glibc23/bin/comp_err
    mysql-5.0.83-linux-i686-glibc23/bin/replace
    mysql-5.0.83-linux-i686-glibc23/bin/perror
    mysql-5.0.83-linux-i686-glibc23/bin/resolveip
    mysql-5.0.83-linux-i686-glibc23/bin/my_print_defaults
    .
    .
    .
    [root@test local]# ll
    total 120908
    drwxr-xr-x 14 7155 wheel      4096 May 30 05:24 mysql-5.0.83-linux-i686-glibc23
    -rwxr-xr-x  1 root root  123603074 Jul 29 18:57 mysql-5.0.83-linux-i686-glibc23.tar.gz

    5、删除源文件tar.gz
    [root@test local]# rm -rf mysql-5.0.83-linux-i686-glibc23.tar.gz

    6、建立符号链接,如果以后有新版本的MySQL 的话,你可以仅仅将源码解压到新
    的路径,然后重新做一个符号链接就可以了。这样非常方便,数据也更加安全。
    [root@test local]# ln -s mysql-5.0.83-linux-i686-glibc23/ mysql
    [root@test local]# ll
    total 76
    lrwxrwxrwx  1 root root    32 Jul 29 19:04 mysql -> mysql-5.0.83-linux-i686-glibc23/
    drwxr-xr-x 14 7155 wheel 4096 May 30 05:24 mysql-5.0.83-linux-i686-glibc23

    7、添加用于启动MySQL 的用户及用户组
    [root@test local]# groupadd mysql
    [root@test local]# useradd -g mysql mysql

    8、初始化授权表
    [root@test mysql]# scripts/mysql_install_db --user=mysql --datadir=/usr/local/mysql/data
    Installing MySQL system tables...
    OK
    Filling help tables...
    OK
    .
    .
    .

    9、设置mysql和root 的访问权限

    设定root能访问/usr/local/mysql   执行命令:[root@test local]# chown -R root .

    设定mysql能访问/usr/local/mysql/ 执行命令:[root@test local]# chown -R mysql .

    设定mysql组能访问/usr/local/mysql 执行命令: [root@test local]# chgrp -R mysql .

    或者

    [root@test local]# cd /usr/local
    [root@test local]# chgrp –R mysql mysql-5.0.83-linux-i686-glibc23
    [root@test local]# chgrp –R mysql .
    [root@test local]# chown -R mysql mysql-5.0.83-linux-i686-glibc23/data
    [root@test local]# chown -R mysql mysql/data

    10、创建bin的符号链接
    [root@test local]# ln -s /usr/local/mysql/bin/* /usr/local/bin/
    [root@test local]# ll
    total 76
    drwxr-xr-x  2 root  mysql 4096 Jul 29 19:18 bin
    lrwxrwxrwx  1 mysql mysql   32 Jul 29 19:04 mysql -> mysql-5.0.83-linux-i686-glibc23/
    drwxr-xr-x 14 mysql mysql 4096 May 30 05:24 mysql-5.0.83-linux-i686-glibc23

    11、复制mysql配置文件以及启动服务文件
    [root@test local]]# cp -r /usr/local/mysql/support-files/my-medium.cnf /etc/my.cnf
    cp: overwrite `/etc/my.cnf'? y
    [root@test local]]# cp /usr/local/mysql/support-files/mysql.server  /etc/rc.d/init.d/mysqld

    12、设置开机自启动

    [root@test support-files]# chkconfig  --add mysqld
    [root@test support-files]# chkconfig  --level 2345 mysqld on

    13、运行mysql:
    [root@test support-files]# /usr/local/mysql/bin/mysqld_safe –user=mysql &
    [1] 5923
    [root@test support-files]# Starting mysqld daemon with databases from /usr/local/mysql/data
    STOPPING server from pid file /usr/local/mysql/data/test.pid
    090729 19:26:44  mysqld ended
    出现上述信息表示启动成功

    14、启动mysqld服务
    [root@test mysql]# service mysqld start
    Starting MySQL.[  OK  ]
    出现ok表示启动成功

    15、检测mysql是否成功启动可以使用如下命令
    [root@test mysql]# /usr/local/mysql/bin/mysqladmin  ping
    mysqld is alive
    [root@test mysql]# /usr/local/mysql/bin/mysqladmin  version
    /usr/local/mysql/bin/mysqladmin  Ver 8.41 Distrib 5.0.83, for pc-linux-gnu on i686
    Copyright (C) 2000-2006 MySQL AB
    This software comes with ABSOLUTELY NO WARRANTY. This is free software,
    and you are welcome to modify and redistribute it under the GPL license

    Server version          5.0.83-log
    Protocol version        10
    Connection              Localhost via UNIX socket
    UNIX socket             /tmp/mysql.sock
    Uptime:                 1 min 20 sec

    Threads: 1  Questions: 2  Slow queries: 0  Opens: 12  Flush tables: 1  Open tables: 6  Queries per second avg: 0.025

    16、设置登录mysql账户的密码:
    [root@test mysql]# /usr/local/mysql/bin/mysqladmin -u root password "manager"

    17、登录mysql

    [root@test ~]# mysql -u root -p
    Enter password:
    Welcome to the MySQL monitor.  Commands end with ; or \g.
    Your MySQL connection id is 2
    Server version: 5.0.83-log MySQL Community Server (GPL)

    Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

    mysql> exit
    Bye

    以上信息表示登录成功

    18、如果在执行第17步的时候出现错误,很可能是因为路径问题,这时就可以设置PATH环境变量,如果可以直接登录成功就无需该步骤了

    [root@test mysql]# vi /etc/profile
    HOSTNAME=`/bin/hostname`
    HISTSIZE=1000
    JAVA_HOME=/usr/java/jdk1.6.0_14
    MYSQL_HOME=/usr/local/bin
    PATH=$PATH:$JAVA_HOME/bin:$JAVA_HOME/jre/bin:$JAVA_HOME/bin
    CLASSPATH=.:$JAVA_HOME/lib:$JAVA_HOME/jre/lib:$CLASSPATH
    if [ -z "$INPUTRC" -a ! -f "$HOME/.inputrc" ]; then
        INPUTRC=/etc/inputrc
    fi

    export PATH USER LOGNAME MAIL HOSTNAME HISTSIZE INPUTRC JAVA_HOME CLASSPATH MYSQL_HOME

  • Windows下使用Jconsole远程监控Linux系统中java服务器资源占用情况

    2009-06-22 15:37:59

    1、首先需要停止正在运行的服务:resin-XXX stop

     

    2、然后在Linux的服务器启动项中添加如下信息:

    -Djava.rmi.server.hostname=192.168.1.122

    -Dcom.sun.management.jmxremote  

    -Dcom.sun.management.jmxremote.port=911
    -Dcom.sun.management.jmxremote.ssl=false
    -Dcom.sun.management.jmxremote.authenticate=false


    比如说我需要了解在压力测试过程中Linux系统中resin服务器的资源占用情况,那么我就可以在resin的启动项中加入上述信息,这样通过本机WindowsJDKJconsole来监控了。

     

    其中第一个参数可以用来设置欲连接的Linux机器的IP地址,该项必须设置,否则远程连接会因为解析到127.0.0.1出现连接失败的情况。

    如果不设置该项,也可以通过修改Linux/etc/hosts文件,使hostname -i 指向正确的IP,所以还是该选项更为方便。

     

    第三个参数是设置欲连接到Linux机器上的端口号,在不跟Linux中现有端口冲突的情况下,可随意设置该端口

     

    3、重新启动服务resin-XXX start


    4、最后双击本机..\jdk1.6\bin\jconsole.exe,启动Jconsole监控界面,在远程连接处输入:192.168.1.122:911,输入Linux主机的用户名和密码,连接即可,因为第2点中的第5-Dcom.sun.management.jmxremote.authenticate=false,设置成了false,所以如果不知道Linux机器的用户名和密码,也可以不输入,直接连接

     

    综上所述,该问题就解决啦,用户Jconsole来监控java服务器的资源占用情况,非常方便直观高效。


    linux下Tomcat配置:

    在tomcat的bin目录下catalina.sh启动项中JAVA_OPTS被正式调用之前,添加如下代

    码:

    JAVA_OPTS="$JAVA_OPTS -server -Xms128m -Xmx512m -XX:PermSize=128m -

    XX:MaxNewSize=256m -Djava.rmi.server.hostname=192.168.1.160 -

    Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=911 -

    Dcom.sun.management.jmxremote.ssl=false -

    Dcom.sun.management.jmxremote.authenticate=false"

    加入没有使用vi,而是用UE编辑,则保存需要转码(FILE->转换->DOS TO UNIX)的形式并保存,可解决文件编码不对引起的bash

    脚本无法执行的问题
    [root@localhost bin]# ./startup.sh
    ./startup.sh: /usr/local/tomcat-6.0.29/bin/catalina.sh: /bin/sh^M: bad

    interpreter: 没有那个文件或目录
    ./startup.sh: line 64: /usr/local/tomcat-6.0.29/bin/catalina.sh: 成功

    重启tomcat

     

  • LINUX系统性能监测工具sysstat的安装

    2009-06-09 13:13:27

    LINUX系统性能监测工具sysstat的安装

    1、下载sysstat的tar.gz包
    链接地址:http://pagesperso-orange.fr/sebastien.godard/download.html
    如果可以直接链接到网络的话,可以使用apt-get install sysstat命令进行安装

    2、安装
     
      tar zxvf  xxx.tar.gz 
      ./configure       
       make
       make install

    安装完成后,用户sar 2 5测试,不行,删除文件重新安装,发现在./configure的时候出现三个warning,并且在make的时候,很多文件被忽略了,特别是.o文件,从网上搜索,需要安装gettext

    因为在虚拟机上,不能直接连接到网络,所以选择了下载gettext-xxx.deb后安装,如果可以上网的话,可以直接使用
    apt-get install gettext
    进行安装

  • “苍蝇式的战斗精神”和“XX性能测试”

    2009-03-16 17:40:43

    “苍蝇式的战斗精神”和“XXX性能测试”

     

    前言:

    XXX性能测试终于告一段落了,心情也轻松了许多,感觉一块大石头落地了。从先前的协助调优,到之后的天天熬性能,前前后后断断续续几个月的时间,总算媳妇熬成婆了。这么长的时间,咱不能白忙活了呀,总得把学到的想到的听到的以后可能会用到的记录下来,与天下人共享,这才叫“境界”,O(_)O哈哈~。借用曹雪芹老先生的话“满纸荒唐言,一把辛酸泪”,当然我这份资料可是绝对滴“不荒唐”,反倒是“粉实在粉实在”。这可是第一手资料哦,值得珍藏ing(*^__^*) 嘻嘻……

     

    不过“辛酸”的的确确是真实的,现在俺只能告诉各位看官“辛酸”的滋味真滴不好受。曾经有那么一段时间,俺是真的失望了,对整个性能的失望,甚至是对自己的绝望,特打击自信滴。俺就像一只没头苍蝇,天天面对着LoadRunner不停的乱试。那时候真的都不知道自己还能做什么了,还会做什么了,曾经一度没有了方向,整个人都要垮掉了,提不起精神,觉得自己特没用,这也许就是所谓的“挫败感”吧。不知各位看官是否有过类似的感受,如有过那咱们先握个手吧,兄弟,知己呀。如果没有,我向您致敬,您运气真好O(_)O~

     

    还好,俺这“苍蝇式的战斗精神”总算感动了上天,本以为看不到头了,没得救了,突然那么一天,上帝眷顾俺咧,怜悯俺咧,这么好的一个娃儿,不能就让她这么废的老,让性能好起来吧,性能就真的好啦O(_)O ~。哈哈,开个玩笑,It is just a story!其实主要是想告诉大家,遇到任何事情都不要回避气馁,坚持一点,再坚持一点,也许就会“柳暗花明又一村”咯。当然,我们性能的优化经历了千辛万苦,与“苍蝇式的探索”和开发兄弟们的辛苦努力是分不开滴。为了纪念“苍蝇”兄弟给俺的启发,特地以此命名。

     

    正文:

    言归正转,下面就把俺这段时间所学所想所感记录下来,让“苍蝇精神”永垂千古(*^__^*) ……

     

    (一)总体统筹

    1、作为性能测试,挖掘用户需求是非常重要的。

    对客户来讲,他可能只需要知道这个页面我要几秒钟就能看到,不能低于几秒钟,超过几秒我就接受不了了。或者说我需要这个系统能支持多少用户,以后公司发展了,还需要支持更多的用户使用等等。

    这个时候我们就要进行需求的分析和细化,把这个几秒钟、多少个用户具体的整理归纳成性能测试所需要的东西。有效的性能测试需求分析才是整个性能测试过程中的重中之重。

    2、性能需求固然重要,更重要的还要做好性能测试计划,测试计划可以说是整个项目的总指挥。

    这个计划不应该是泛泛而谈,为应付而应付的东西。它不仅仅应该是测试计划,更应该是计划测试。计划测试就是要让测试活起来,有生气,有内容。

    经过XXX的测试,个人觉得性能测试计划最好使用Excel表格,这样便于及时的记录结果、修订内容,而且看起来会非常的清晰。XXX性能测试计划我是跟测试用例整理到一起的,详见附件《XXX性能测试计划.xls》,仅供参考。 

    3、一定要有测试用例,如果说测试计划是总指挥的话,测试用例就是总指挥手中的魔法棒,它指导着用户的操作过程。

    因为性能测试比较繁琐,可能需要不停的反复,因此测试用例要做到及时更新,并且必须要及时的记录一些重点的测试结果。“好脑筋不如烂笔头”,记录下来就不容易忘记了,而且也能更好的做到有据可循。

    众所周知,凡是有人的地方就会有矛盾,就会有责任的纷争和归属,如果有据可循,就避免了大量麻烦。其实这种事情我想每个做测试的兄弟姐妹们都应该遇到过,尤其是功能测试的时候。系统上线啦,咱们的辛劳没人太在意,一旦系统出了问题,得啦,好日子来啦,测试是怎么做的,这种问题怎么没有测到。嗳,这个时候如果有证据说明你确实做过了,而且是没有问题的,那自然就……当然,这也不能成为我们推卸责任的理由,出现问题了,还是需要积极的去面对,及时的去修正,不管是不是你的责任。

    (二)细节把握

    1、录制脚本前要先熟悉系统,这样才能做到“知己知彼,百战不殆”。其实不需要这么冠冕堂皇的理由,如果连系统都不熟悉,“丈二和尚摸不着头”的,谈何而来的脚本录制。

    2、脚本要优化。脚本不是录制完就算完事了,就可以使用了,而是要根据需要进行优化,脚本分割、创建事务、参数化等等。我在实际过程中总结了下面几点:

    1)脚本删减。因为LoadRunner是模拟用户之间的通信过程的,不是所有的脚本都是必需的,事实上有些垃圾代码可能会影响性能测试结果的准确性。因此可以对脚本进行删减,只保留关键部分。删减的过程中需要注意的是如果你不确定,可以先把不需要的脚本注释掉,然后在VUGen中执行一遍,如果成功执行,这些被注释掉的脚本就可以删除了。

       经过实践发现,脚本中的这些地方是可以删除的:web_add_cookie函数、一些非必须的web_url函数等等,还有每个函数EXTRARES之后LAST之前的部分。或者通过Tree View视图查看,没有Server Response返回值的,或者返回值中的内容对整个脚本无关紧要的,不需要用到它的返回值来做关联或者其他操作的,就都可以删掉。这是个很实用的技巧,屡试不爽。

       有人可能会产生这样的困惑,哎呀,这么删来删去的,万一删错怎么办呢,还要重新录制脚本,岂不是很麻烦。不要着急,试试Regenerate Script…吧,VUGen -> Tools -> Regenerate Script…可以还原到初始脚本哦。

    2)脚本分割。LR的脚本分割具有更强的灵活性,如果有一段内容需要经常被使用到,那么就可以把他单独拎出来,放在一个函数,也就是在Script. View左边Action导航中Create New Action即可。这样就可以随用随调了。

       脚本处理好以后在VUGen中回放时,默认是按照RunTime-Setting -> Run Logic -> Run下面的action顺序执行的,这个时候就会出现问题。比如Run下面有4actionlogin()start()sendMsg()(调用start())、logout(),其中只需要在sendMsg的时候调用一次start就可以了,按照目前的顺序回放的话,start()就被多执行了一次。要解决这个问题,只需要将start()RunTime-Setting -> Run Logic -> Run中删除即可。回到Script. View左边Action导航可以看到start()的图标变成了半透明状,类似“只读”状态,事实上是可以编辑的。这又是一个行之有效的小窍门。

    3)脚本参数化。以前只拘泥于选择file文件类型对脚本进行参数化,后来发现file类型太麻烦了,特别是大数据量的时候,如果不是必须用的话,建议选择其他的类型。比如说XXX项目中,对Server的参数化就是选择在server0server1还是server2上执行,先前都是采用file类型,因为最多要有1500个用户并发,所以要在file中准备1500条数据,这样就是一个比较大的工作量,尽管用excel拖曳一下也蛮方便的。事实上,我只需要对012做参数化就行了,所以使用Random Number类型就更方便啦,而且通过压力测试发现,这种参数处理方式可以使各台服务器的负载更加均衡。强调这一点并不是说file类型不好,而是说在进行参数化的时候要结合实际,做最有效的处理。其实对于参数化已经讲了不止一次了,每次都有新的内容,关键是要用,在用的过程中才能做到“融会贯通,游刃有余”。

    4)脚本关联方式。脚本的关联是在脚本处理过程中经常用到的,他可以自动关联,也可以手动关联。可以参考鄙人以前写的《在LoadRunner中用web_reg_save_param()做关联》,除了该文档中编写的方法外,鄙人还发现一个查找关联点的方法,那就是在脚本回放的时候选择打开浏览器Tools->General Options->Display->Show browser during replay,这样就会将新一轮的回放结果显示在浏览器中,很明了的就可以查看了。如果对系统比较熟悉,关联就会变得非常简单了。

    3、场景设计。场景设计是非常重要的,这个更多的依赖于性能需求,想要什么样的结果就做什么样的设计。在此次的测试过程中发现,场景开始执行时如果同时有100个用户并发操作,就会出现大量的连接超时,服务器无法响应,或者连接被过早的关闭等错误,这个时候就需要寻求最佳的并发用户数量,因为有多台客户端,所以在设计场景时就需要仔细计算每个客户端的并发用户数量,并且需要保证每次接收和发送消息的并发用户数量是相同的。具体可参见附件《XXX性能测试报告.pdf》中的场景设计图。

    4Run-tXXXe Setting设置。因为要保证每个用户都必须成功登录,所以在登录脚本中做了条件判断,如果用户的ID和应用ID等不为空,就表示登录成功了,如果为空就重新登录,这个时候MiscellaneousContinue on error选项就需要被勾选,这样就可以保证每个用户都能成功登录了。

       Preferences -> Options里面,step timeout caused by resources is a warning 设置为yes,这样资源下载失败了就会显示为一个警告,就不会在场景中出现大量的error

       Preferences -> Options里面,step download timeout (sec)可以设置的时间长一点,比如说300s,这样就保证了资源下载的时间,资源下载失败的现象也会减少。 

       同时需要在场景的Tools -> Options -> Timeout做一些超时时间限制的调整。

       如果基本上知道结果输出可能的情况,就可以General -> Log设置Send messages only when an errors occurs,也就是仅在错误时候输出日志。如果需要查看所有的日志输出,可以选择Always send messages

    5、场景定时运行。有时候可能并不需要场景设置好了马上就执行,而是希望在某个时间点开始。这个时候可以选择场景中的Edit Schedule -> Scenario Start Time,设置为At (HH:MM:SS) on (yyyy-mm-dd)执行。此时需要注意的是,一定要点 Start Scenario

    6、结果文件的命名和保存。场景执行后势必会产生结果文件,结果文件的命名需要规范易于分辨。如上第4点,如果选择Always send messages,那么光日志文件就可能占据很大的空间,把结果文件制作成HTML Report的形式就会节省很大的空间。在Analysis中整理好所需要的结果图表,选择Analysis -> Reports -> HTML Report即可。

    7、使用多台客户端作为Load Generators为保证每台机器都能正常连接,各客户端的LoadRunner Agent Process都是开启的,然后在场景开始之前需要先Connect每台客户端。

    多台客户端机器作为Load Generators时,除了主控机,也就是执行场景的机器,LoadRunner会在各个客户端机器的临时文件夹中生成很大的文件,有的多大10几个G,文件的大小跟场景执行时间成正比。因此场景开始之前,一定要保证各客户机的磁盘空间充足。

    (三)结果分析

    个人认为结果分析是一个长期的过程,更应该是一个集体合作的结晶。由于个人知识结构的限制,分析的难免不到位,附上测试报告,仅供分享。

      此次测试,主要关注了事务的响应时间、吞吐量和服务器的资源占用率等几个方面的指标。

     1、事务正常运行的时候,如果响应时间曲线持续上升,点击率和吞吐量曲线都在下降,可能表明系统的处理能力在下降。引起该现象的原因可能有:(1)用户数连接未做限制,导致请求数不断上升,响应时间不断变长。(2)出现内存泄露。

     2CPU的使用率不断上升,内存的使用率也是不断上升,其他一切都很正常,表明系统中可能产生资源争用。

     3、 所有的事务响应时间、cpu等指标都很正常,大量的业务失败,可能是由于数据库死锁造成的,也就是说,你在操作一张表或一条记录,别人就不能使用,即数据存在互斥性,当数据量大时,就会出现数据错乱的情况。

    (四)相关知识

       性能测试真是一个考验所有相关人员,尤其是测试人员各方面能力的活计。做好性能测试需要具备各方面的知识,不一定全部精通,但至少都要懂一点。专业的测试技能、软件编程能力、网络知识、操作系统、数据库、中间件、行业知识、个人素养等等。

    在网络方面,测试人员应该掌握基本的网络协议以及网络工作原理。尤其要掌握一些网络环境的配置知识,这些都是测试工作中经常用到的知识。

    操作系统和中间件方面,应该掌握基本的使用、安装及配置等技能。例如,很多应用系统都是基于UnixLinux来运行的,这就要求测试人员掌握其基本的操作命令以及相关工具软件的使用。而WebLogicWebsphere等中间件的安装与配置方法也需要掌握一些。

    数据库知识则是更应该掌握的基础知识。现在的应用系统几乎离不开数据库。因此,不但要掌握基本的安装、配置,还要掌握SQL。测试人员至少应该掌握MysqlMS SqlServerOracle等常见数据库的使用。

    作为一名优秀的测试工程师,首先要对测试工作有兴趣,因为测试工作在很多时候多少显得有些枯燥。因此,先要热爱测试工作,才能做好测试工作。在个人素养方面,除了具备必须的专业技能和行业知识外,测试人员还应该具有一些基本的品质:专心+细心+耐心+责任心+自信心 ,统称为五心

    如此看来,要真正的做好性能测试,还有很大一段距离,有差距才有动力,有动力才有进步的空间,加油!

    尾声:

      终于接近尾声了,希望这篇《“苍蝇式的战斗精神”和“XXX性能测试”》能给大家带来一点点的帮助。

     

983/5<12345>
Open Toolbar