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上,點選連結可以預覽。這個我之前也沒有做過,先研究下,有知道的同學可以告訴我哈。