1. 程式人生 > >Jenkins高階篇之Pipeline實踐篇-6-Selenium和Jenkins持續整合-pipeline引數化構建selenium自動化測試

Jenkins高階篇之Pipeline實踐篇-6-Selenium和Jenkins持續整合-pipeline引數化構建selenium自動化測試

       這篇來思考下如何寫一個方法,可以修改config.properties檔案裡面的屬性。加入這個方法可以根據key修改value,那麼我們就可以通過jenkins上變數,讓使用者輸入,來修改config.properties檔案裡面的值。例如測試伺服器地址和瀏覽器型別的名稱。如果使用者在Jenkins介面填寫瀏覽器是chrome,那麼我們就修改config.properties裡面的browser=chrome,如果使用者填寫的是firefox,那麼我們就在啟動selenium測試之前去修改browser=firefox。這樣,靈活的控制引數,就達到了我們第一個需求。

1.根據Java的方法

我們知道grooy是可以無縫執行java程式碼,我也寫了一個java的程式碼,放在pipleline/selenium.groovy檔案裡,結果我在測試的時候,報了一個錯誤,這個需要jenkins管理員去approve這個指令碼的執行,但是我的jenkins環境上沒有這個approve的相關的script,很神奇。

import hudson.model.*;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Properties;


def setKeyValue(key, value, file_path) {
    Properties prop = new Properties()
    try {
        prop.load(new FileInputStream(file_path))
    }catch (FileNotFoundException e){
        e.printStackTrace()
    }catch (IOException e) {
        e.printStackTrace()
    }
    
    // write into file 
    try {
        prop.setProperty(key, value)
	    FileOutputStream fos = new FileOutputStream(file_path)
        prop.store(fos, null)
        fos.close()
    }catch (FileNotFoundException e){
        e.printStackTrace()
    }catch (IOException e) {
        e.printStackTrace()
    }
}

return this;

結果測試下,報了一個沙箱錯誤:

ERROR: Error met:org.jenkinsci.plugins.scriptsecurity.sandbox.RejectedAccessException: Scripts not permitted to use new java.util.Properties

其實,這個類似錯誤,我在工作中也遇到過,一般來說管理員去點選批准這個指令碼執行就可以。我的環境,在升級一個script security相關的外掛之後,連指令碼批准入口都不顯示了,很神奇。只好換一種思路去寫程式碼了。

2.Pipeline自帶的readFile和writeFile

我的思路是這樣的,先通過readFile方法獲取到原來檔案的內容,返回是一個字串物件。然後根據換行符把字串物件給切片,拿到一個list物件,遍歷這個list,用if判斷,根據Key找到這行,然後改寫這行。由於這我們只是在記憶體改寫,所以需要提前定義一個list物件來把改寫和沒有改寫的都給add到新list,然後定義一個空字串,遍歷新list,每次拼接一個list元素都加上換行符。這樣得到字串就是一個完整內容,然後把這個內容利用writeFile方法寫回到原來的config檔案。

具體程式碼是這樣的。

selenium_jenkins.groovy檔案

import hudson.model.*;

pipeline{

    agent any
    parameters {
        string(name: 'BROWSER_TYPE', defaultValue: 'chrome', description: 'Type a browser type, should be chrome/firefox')
        string(name: 'TEST_SERVER_URL', defaultValue: '', description: 'Type the test server url')
        string(name: 'NODE', defaultValue: 'win-anthony-demo', description: 'Please choose a windows node to execute this job.')
    }
    
	stages{
	    stage("Initialization"){
	        steps{
	            script{
	                browser = BROWSER_TYPE?.trim()
	                test_url = TEST_SERVER_URL?.trim()
	                win_node = NODE?.trim()
	            }
	        }
	    }

	    stage("Git Checkout"){
	        steps{
	            script{
	                node(win_node) {
	                     checkout([$class: 'GitSCM', branches: [[name: '*/master']],
						    userRemoteConfigs: [[credentialsId: '6f4fa66c-eb02-46dc-a4b3-3a232be5ef6e', 
							url: 'https://github.com/QAAutomationLearn/JavaAutomationFramework.git']]])
	                }
	            }
	        }
	    }
	    
        stage("Set key value"){
	        steps{
	            script{
	                node(win_node){
	                    selenium_test = load env.WORKSPACE + "\\pipeline\\selenium.groovy"
	                    config_file = env.WORKSPACE + "\\Configs\\config.properties"
	                    try{
	                        selenium_test.setKeyValue2("browser", "abc123", config_file)
	                        file_content = readFile config_file
                            println file_content
	                    }catch (Exception e) {
	                        error("Error met:" + e)
	                    }
	                }
	            }
	        }
	    }
	    
	    stage("Run Selenium Test"){
	        steps{
	            script{
	                node(win_node){
	                    println "Here will start to run selenium test."
	                }
	            }
	        }
	    }
	}



}

selenium.groovy檔案

import hudson.model.*;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Properties;


def setKeyValue(key, value, file_path) {
    Properties prop = new Properties()
    try {
        prop.load(new FileInputStream(file_path))
    }catch (FileNotFoundException e){
        e.printStackTrace()
    }catch (IOException e) {
        e.printStackTrace()
    }
    
    // write into file 
    try {
        prop.setProperty(key, value)
	    FileOutputStream fos = new FileOutputStream(file_path)
        prop.store(fos, null)
        fos.close()
    }catch (FileNotFoundException e){
        e.printStackTrace()
    }catch (IOException e) {
        e.printStackTrace()
    }
}

def setKeyValue2(key, value, file_path) {
    // read file, get string object
    file_content_old = readFile file_path
    println file_content_old
    //遍歷每一行,判斷,然後替換字串
    lines = file_content_old.tokenize("\n")
    new_lines = []
    lines.each { line ->
        if(line.trim().startsWith(key)) {
            line = key + "=" + value
            new_lines.add(line)
        }else {
            new_lines.add(line)
        }
    }
    // write into file
    file_content_new = ""
    new_lines.each{line ->
        file_content_new += line + "\n"
    }

    writeFile file: file_path, text: file_content_new, encoding: "UTF-8"
}
return this;

這裡看第二個方法是我的思路,雖然比較囉嗦,但是實現了這個修改檔案的需求。

測試結果看看是否把browser = chrome 改成browser = abc123

[Pipeline] readFile
[Pipeline] echo
baseURL=http://demo.guru99.com/v4/index.php
# https://www.utest.com  backup website
userName=mngr169501
password=sYhYtUd

# browser driver path
firefoxpath=./Drivers\\geckodriver.exe
chromepath=./Drivers\\chromedriver.exe

# browser instance
# the browser vlaue will only be firefox or chrome here
browser=chrome


[Pipeline] writeFile
[Pipeline] readFile
[Pipeline] echo
baseURL=http://demo.guru99.com/v4/index.php
# https://www.utest.com  backup website
userName=mngr169501
password=sYhYtUd

# browser driver path
firefoxpath=./Drivers\\geckodriver.exe
chromepath=./Drivers\\chromedriver.exe

# browser instance
# the browser vlaue will only be firefox or chrome here
browser=abc123


[Pipeline] }
[Pipeline] // node

你如果對日誌不放心,你可以去你拉取之後程式碼路徑去看看是否修改了,修改的對不對。

接下來,我把github裡面config.properties 中browser的值改成firefox,然後我通過pipeline程式碼去改成chrome,來跑一個整合測試,看看行不行,測試環境URL就無法改,這個沒有第二套同樣產品的地址,這個就留個你們自己專案上的測試環境和生產環境,自己試一下。

提交之後,兩個檔案程式碼如下

import hudson.model.*;

pipeline{

    agent any
    parameters {
        string(name: 'BROWSER_TYPE', defaultValue: 'chrome', description: 'Type a browser type, should be chrome/firefox')
        string(name: 'TEST_SERVER_URL', defaultValue: '', description: 'Type the test server url')
        string(name: 'NODE', defaultValue: 'win-anthony-demo', description: 'Please choose a windows node to execute this job.')
    }
    
	stages{
	    stage("Initialization"){
	        steps{
	            script{
	                browser_type = BROWSER_TYPE?.trim()
	                test_url = TEST_SERVER_URL?.trim()
	                win_node = NODE?.trim()
	            }
	        }
	    }

	    stage("Git Checkout"){
	        steps{
	            script{
	                node(win_node) {
	                     checkout([$class: 'GitSCM', branches: [[name: '*/master']],
						    userRemoteConfigs: [[credentialsId: '6f4fa66c-eb02-46dc-a4b3-3a232be5ef6e', 
							url: 'https://github.com/QAAutomationLearn/JavaAutomationFramework.git']]])
	                }
	            }
	        }
	    }
	    
        stage("Set key value"){
	        steps{
	            script{
	                node(win_node){
	                    selenium_test = load env.WORKSPACE + "\\pipeline\\selenium.groovy"
	                    config_file = env.WORKSPACE + "\\Configs\\config.properties"
	                    try{
	                        selenium_test.setKeyValue2("browser", browser_type, config_file)
	                        //test_url 你自己替代
	                        file_content = readFile config_file
                            println file_content
	                    }catch (Exception e) {
	                        error("Error met:" + e)
	                    }
	                }
	            }
	        }
	    }
	    
	    stage("Run Selenium Test"){
	        steps{
	            script{
	                node(win_node){
	                    run_bat = env.WORKSPACE + "\\run.bat"
	                    bat (run_bat)
	                }
	            }
	        }
	    }
	}



}
import hudson.model.*;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Properties;

def setKeyValue(key, value, file_path) {
    // read file, get string object
    file_content_old = readFile file_path
    println file_content_old
    //遍歷每一行,判斷,然後替換字串
    lines = file_content_old.tokenize("\n")
    new_lines = []
    lines.each { line ->
        if(line.trim().startsWith(key)) {
            line = key + "=" + value
            new_lines.add(line)
        }else {
            new_lines.add(line)
        }
    }
    // write into file
    file_content_new = ""
    new_lines.each{line ->
        file_content_new += line + "\n"
    }

    writeFile file: file_path, text: file_content_new, encoding: "UTF-8"
}
return this;

測試結果:

http://65.49.216.200:8080/job/selenium-pipeline-demo/23/console

主要日誌如下:

[Pipeline] node
Running on win-anthony-demo in C:\JenkinsNode\workspace\selenium-pipeline-demo
[Pipeline] {
[Pipeline] load
[Pipeline] { (C:\JenkinsNode\workspace\selenium-pipeline-demo\pipeline\selenium.groovy)
[Pipeline] }
[Pipeline] // load
[Pipeline] readFile
[Pipeline] echo
baseURL=http://demo.guru99.com/v4/index.php
# https://www.utest.com  backup website
userName=mngr169501
password=sYhYtUd

# browser driver path
firefoxpath=./Drivers\\geckodriver.exe
chromepath=./Drivers\\chromedriver.exe

# browser instance
# the browser vlaue will only be firefox or chrome here
browser=chrome


[Pipeline] writeFile
[Pipeline] readFile
[Pipeline] echo
baseURL=http://demo.guru99.com/v4/index.php
# https://www.utest.com  backup website
userName=mngr169501
password=sYhYtUd

# browser driver path
firefoxpath=./Drivers\\geckodriver.exe
chromepath=./Drivers\\chromedriver.exe

# browser instance
# the browser vlaue will only be firefox or chrome here
browser=chrome


[Pipeline] }
[Pipeline] // node
[Pipeline] }
[Pipeline] // script
[Pipeline] }
[Pipeline] // stage
[Pipeline] stage
[Pipeline] { (Run Selenium Test)
[Pipeline] script
[Pipeline] {
[Pipeline] node
Running on win-anthony-demo in C:\JenkinsNode\workspace\selenium-pipeline-demo
[Pipeline] {
[Pipeline] bat
[selenium-pipeline-demo] Running batch script
C:\JenkinsNode\workspace\selenium-pipeline-demo>C:\JenkinsNode\workspace\selenium-pipeline-demo\run.bat

C:\JenkinsNode\workspace\selenium-pipeline-demo>cd C:\Users\Anthont\git\AnthonyWebAutoDemo 

C:\Users\Anthont\git\AnthonyWebAutoDemo>mvn clean install 
[INFO] Scanning for projects...
[WARNING] 
[WARNING] Some problems were encountered while building the effective model for AnthonyAutoV10:AnthonyAutoV10:jar:0.0.1-SNAPSHOT
[WARNING] 'build.plugins.plugin.version' for org.apache.maven.plugins:maven-compiler-plugin is missing. @ line 19, column 15
[WARNING] 
[WARNING] It is highly recommended to fix these problems because they threaten the stability of your build.
[WARNING] 
[WARNING] For this reason, future Maven versions might no longer support building such malformed projects.
[WARNING] 
[INFO] 
[INFO] -------------------< AnthonyAutoV10:AnthonyAutoV10 >--------------------
[INFO] Building AnthonyAutoV10 0.0.1-SNAPSHOT
[INFO] --------------------------------[ jar ]---------------------------------
[WARNING] The POM for com.beust:jcommander:jar:1.66 is missing, no dependency information available
[INFO] 
[INFO] --- maven-clean-plugin:2.5:clean (default-clean) @ AnthonyAutoV10 ---
[INFO] Deleting C:\Users\Anthont\git\AnthonyWebAutoDemo\target
[INFO] 
[INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ AnthonyAutoV10 ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] skip non existing resourceDirectory C:\Users\Anthont\git\AnthonyWebAutoDemo\src\main\resources
[INFO] 
[INFO] --- maven-compiler-plugin:3.1:compile (default-compile) @ AnthonyAutoV10 ---
[INFO] Nothing to compile - all classes are up to date
[INFO] 
[INFO] --- maven-resources-plugin:2.6:testResources (default-testResources) @ AnthonyAutoV10 ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] skip non existing resourceDirectory C:\Users\Anthont\git\AnthonyWebAutoDemo\src\test\resources
[INFO] 
[INFO] --- maven-compiler-plugin:3.1:testCompile (default-testCompile) @ AnthonyAutoV10 ---
[INFO] Changes detected - recompiling the module!
[INFO] Compiling 11 source files to C:\Users\Anthont\git\AnthonyWebAutoDemo\target\test-classes
[INFO] 
[INFO] --- maven-surefire-plugin:2.18.1:test (default-test) @ AnthonyAutoV10 ---
[INFO] Surefire report directory: C:\Users\Anthont\git\AnthonyWebAutoDemo\target\surefire-reports

-------------------------------------------------------
 T E S T S
-------------------------------------------------------
Running TestSuite
Starting ChromeDriver 2.40.565498 (ea082db3280dd6843ebfb08a625e3eb905c4f5ab) on port 1780
Only local connections are allowed.
Dec 23, 2018 9:52:43 PM org.openqa.selenium.remote.ProtocolHandshake createSession
INFO: Detected dialect: OSS
 INFO [main] (TC_NewCustomer_004.java:22)- Login is completed
 INFO [main] (TC_NewCustomer_004.java:28)- Proving customer details.............
 INFO [main] (TC_NewCustomer_004.java:46)- Validating adding new customer..............
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 166.426 sec - in TestSuite

Results :

Tests run: 1, Failures: 0, Errors: 0, Skipped: 0

[INFO] 
[INFO] --- maven-jar-plugin:2.4:jar (default-jar) @ AnthonyAutoV10 ---
[WARNING] JAR will be empty - no content was marked for inclusion!
[INFO] Building jar: C:\Users\Anthont\git\AnthonyWebAutoDemo\target\AnthonyAutoV10-0.0.1-SNAPSHOT.jar
[INFO] 
[INFO] --- maven-install-plugin:2.4:install (default-install) @ AnthonyAutoV10 ---
[INFO] Installing C:\Users\Anthont\git\AnthonyWebAutoDemo\target\AnthonyAutoV10-0.0.1-SNAPSHOT.jar to C:\Users\Anthont\.m2\repository\AnthonyAutoV10\AnthonyAutoV10\0.0.1-SNAPSHOT\AnthonyAutoV10-0.0.1-SNAPSHOT.jar
[INFO] Installing C:\Users\Anthont\git\AnthonyWebAutoDemo\pom.xml to C:\Users\Anthont\.m2\repository\AnthonyAutoV10\AnthonyAutoV10\0.0.1-SNAPSHOT\AnthonyAutoV10-0.0.1-SNAPSHOT.pom
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  03:05 min
[INFO] Finished at: 2018-12-23T21:55:24+08:00
[INFO] ------------------------------------------------------------------------
[Pipeline] }
[Pipeline] // node
[Pipeline] }
[Pipeline] // script
[Pipeline] }
[Pipeline] // stage
[Pipeline] }
[Pipeline] // withEnv
[Pipeline] }
[Pipeline] // node
[Pipeline] End of Pipeline
Finished: SUCCESS

這裡靈活的引數,我們實現了需求。

下一篇文章,我們來思考下如何把測試過程的日誌和報告檔案給放到Jenkins上,點選連結可以預覽。這個我之前也沒有做過,先研究下,有知道的同學可以告訴我哈。