Hudson + WebDriver 组织自动化测试

之前介绍过如何使用TestNG来驱动WebDriver用Ant来自动化运行测试。今天分享一下如何把这些东西都放到HudsonJenkins也行)里面呢?

Hudson是一个比较流行都持续集成工具。用Hudson来驱动自动化测试的好处有以下这些:

  • 类似crontab的自动任务管理
  • 丰富的插件支持
  • 支持分布式任务
  • 容易部署

其实整个过程很简单,把Hudson跑起来,新建一个Job,配置一下Ant任务就好了。这里只分享一下我遇到的一些坑。

是否使用Source Code Management获取最新的测试代码?

如果每次测试都拉最新的代码,好处就是保证测试代码是最新的。但是也会带来一些问题,测试代码本身也是代码,怎么保证最新的测试代码没有问题呢?我个人认为,如果团队比较小,可以直接拉最新的代码;如果团队大,需要控制。

如果不用SCM插件,怎么样更新自动化测试代码?

我想到的一种办法就是,在Hudson里面建立一个构建自动化测试代码的Job,这个Job的产物就是自动化测试的包,譬如说如果用WebDriver或者Selenium,就把测试代码build成一个或者若干个jar包,然后建立一个latest的软链接指向最新的jar包;在运行自动化测试的Job里面做好配置,运行测试的目标jar包就指向latest.jar就OK了。

TestNG的结果如何跟Hudson整合

Hudson插件很多,可以用testng-plugin来完成这个任务。配置比较简单,在Ant脚本里面配置好TestNG的result output,然后在Hudson里面把测试报告的模式填好。我直接填的TestNG的默认结果文件“testng-results.xml”。build.xml节点配置的一个例子:

    
        
            
        
        
    

首先在testng节点指定outputdir属性,然后测试运行完成以后把结果文件移动到Hudson的workspace

怎么样把Ant的参数传递给TestNG

很多时候我们会希望通过ant把一些参数传递给testng.xml,从而使得测试更加灵活。例如传递不用的base_url可以测试不同的站点。还有配置不同的浏览器。虽然之前这篇文章已经介绍了如何把Ant的参数传递给TestNG,但是那个方法有个缺点,如果在测试方法A里面调用了测试方法B,测试方法B是不能拿到Ant传进去的参数的。我的办法比较土,就是首先写好一个testng_base.xml的模板文件,把一些可能经常改变的数值替换成参数,然后用Ant的replace任务做字符串替换。

    
        
        
    

TestNG+Ant自动运行测试

之前一篇博客分享了如何使用WebDriver+TestNG实现UI自动化,现在就要让自动化测试自己跑起来,不需要人工干预。需要用到Ant,以及一些定时任务工具,例如Linux的crontab。

如何在Ant的build.xml里面正确配置TestNG呢?

1. 在build.xml里面定义testng任务,在classpath里面指定testng.jar


2. 在build.xml里面新建一个 叫regression的target


    
    
    
    

    

    
        
    
    
        
        
    

    
        
        
        
    

    
        
            
        
    

在target里面新建一个testng标签,里面需要设置的属性有:outputdir – 测试结果输出目录;classpathref – 那些自动化测试代码的目标路径,通常就是编译完成以后的那个目标路径,例如xxx/bin;delegateCommandSystemProperties – 接受传递命令行参数作为系统变量,这个设置为true可以在调用Ant的时候通过 -Dfoo=value 把参数传递给TestNG;里面还有一个xmlfileset节点,这个节点就是指定testng.xml文件的目录以及具体文件。

regression 的 target 有一个depends属性,意思就是跑regression之前需要做compile,而跑compile之前需要clean,应该很容易理解。直接在命令行里面运行:

ant -Durl=http://www.google.com -f build.xml regression

这里出现了 -Durl=http://www.google.com ,回到之前的配置,delegateCommandSystemProperties=”true”。如果这个参数为true,那么通过命令行的 -D 参数可以把一些变量传递给TestNG。譬如说TestNG的测试方法里面是有@Parameters({“url”})标签的话,就能通过ant -Durl=xxx 来传递url的值给到TestNG。例如

@Parameters({"url"})
@Test
public void search(String url){
    WebDriver driver = new FirefoxDriver();
    driver.get(url);
    WebElement query = driver.findElement(By.name("q"));
    query.sendKeys("Cheese");
    query.submit();
}

如果这样调用:ant -Durl=http://www.google.com -f build regression 。那么就会进入google的首页搜索,如果是: ant -Durl=http://magustest.com -f build regression ,那么就会找不到叫“q”的元素,呵呵。

接下来只要把cron job配好就完成了

15 * * * * ant -f /home/maguschen/workspaces/automation/build.xml regression

WebDriver + TestNG 应用

Selenium 2 已经发布了一个多月,官方版本已经到了Selenium 2.3,并且在Google code里面可以找到2.4的下载。Selenium 2 最大的更新就是集成了WebDriver。这两者是什么关系呢?如果你搜索WebDriver,第一条结果是Selenium。其实WebDriver和Selenium可以说是在实现UI Automation的竞争对手。Selenium是运行在JavaScript的sandbox里面,所以很容易就支持不同的浏览器;而WebDriver则是直接操作浏览器本身,更接近用户的真实操作,但正因为如此,所以WebDriver在多浏览器/操作系统的支持上就要落后于Selenium。不过从Selenium 2开始,这两个项目合并了,可以继续用原来的Selenium,也可以考虑迁移到WebDriver。我个人认为WebDriver应该是以后的大趋势,还是值得迁移的。至于你信不信,我反正是信了。

作为一个轻量级的UI Automation框架,需要写一些驱动它的代码,大部分人会选择JUnit,因为JUnit是单元测试的事实标准;但是我会用TestNG。这些UI Automation的东西,它们本身不是单元测试,而且也没有太多单元测试的风格。

从一段简单的测试开始

public class GoogleTest  {
    @Test
    public void search(ITestContext context) {
        WebDriver driver = new FirefoxDriver();

        driver.get("http://www.google.com");

        WebElement element = driver.findElement(By.name("q"));

        element.sendKeys("magus");
        element.submit();

        Assert.assertTrue(driver.getTitle().contains("magus"), "Something wrong with title");
    }
}

TestNG应用了Java的Annotations,只需要在测试方法上面打上@Test就可以标示出search是一个测试方法。用TestNG运行测试还需要一个testng.xml的文件,文件名其实可以随便起,没有关系的。


    
        
            
                
                    
                
            
        
    


我想让测试更加灵活,1. 可以配置使用任意支持的浏览器进行测试;2. 配置所有Google的URL;3. 配置搜索的关键字。修改后的代码:

public class GoogleTest  {
    WebDriver driver;

    @Parameters({"browser"})
    @BeforeTest
    public void setupBrowser(String browser){
        if (browser.equals("firefox")){
            driver = new FirefoxDriver();
        } else {
            driver = new ChromeDriver();
        }
    }

    @Parameters({ "url", "keyword" })
    @Test
    public void search(String url, String keyword, ITestContext context) {        driver.get(url);
        WebElement element = driver.findElement(By.name("q"));
        element.sendKeys(keyword);
        element.submit();
        Assert.assertTrue(driver.getTitle().contains(keyword), "Something wrong with title");        }
}

testng.xml


    
    
    
    
        
            
                
                    
                    
                
            
        
    

利用TestNG的@Parameters标签,让测试方法从testng.xml里面读取参数,实现参数化。在testng.xml的配置中,test节点需要增加一个属性的配置: preserve-order=”true”。这个preserve-order默认是false,在节点下面的所有方法的执行顺序是无序的。把它设为true以后就能保证在节点下的方法是按照顺序执行的。TestNG的这个功能可以方便我们在testng.xml里面拼装测试。假设我们有很多独立的测试方法,例如

  • navigateCategory
  • addComment
  • addFriend
  • login
  • logout

就可以在testng.xml里面拼出不同的测试,例如


    
        
            
                
                
                
            
        
    


    
        
                            
                
                
                
            
        
    

TestNG比JUnit更加适合做一些非单元测试的事情,不是说JUnit不好,而是不能把JUnit当成万能的锤子,到处钉钉子。WebDriver的API比Selenium的更加简洁,会是以后的大趋势。

之后打算分享一下如何用ant把自动化测试自动化起来。