안녕하세요 테스트링크 및 젠킨스 연동 포스팅도 끝났고


Chrome 브라우저에 대한 자동화 빌드 테스트도 어느정도 마무리가 된것 같습니다. 


사실 연결만 되었고 결과 받고 100프로 다 된것 같지만 고도화 등 마무리 처리를 해주어야 할 작업이 산더미 입니다.


하지만 이 작업들은 여기까지 오셨다면 다들 할수 있을거라 생각하기 때문에 따로 포스팅은 하지 않으려고합니다.


현재 자동화 도식도를 좀더 눈으로 보기 좋게 그려봤습니다



젠킨스가 빌드를 땅 시작합니다.(when a build step) 빌드 유발을 통해서 (이부분은 따로 Jenkins - 빌드 유발로 포스팅하겠습니다.)


그럼 셀레니엄 테스트코드가 있는 최신 master 브랜치에서 코드를 가져온후에 셀레니엄 코드를 실행합니다.


위의 사진에선 파라미터로 Chrome을 넘겼기 때문에 크롬 브라우저가 실행되겠네요 


테스트할 페이지 (top.js -client) 의 아랫단에는 factory 라는 모듈(간단하게 제작)이 있는데 이 해당 모듈은 E2E TestCase 


에 기반하여 사용자 또는 셀레니움이 했던 행동들을 기록하며 리포팅을 해줄수 있도록 되어있습니다. top.js - client에는


테스트의 마지막을 뜻하는 End Point 지점이 있는데요 이 지점이 클릭 됐을 시 연초록색 화살표 대로 발생합니다.


앤드 포인트가 찍히는 시점은 2갠데요 


1. Selenium 이 찍었을때 


.click() 후 작업이  해당 테스트 결과를 Junit-report.xml 형태로 만들어놓습니다.


만드는건 xmlBuilder를 사용하여 직접 간단하게 만들었습니다.


만들어 놓게 되면  셀레니움 빌드가 끝나게 되는데요 그렇게되면 Jenkins에 있는 TestLink Plugin 이  제가 설정한대로


junit -report 파일을 찾습니다. 찾을 때는 설정에 따라 다른데요 저는 classname으로 지정해놨기 때문에


classname이 Custom Field랑 같은 경우를 찾습니다.


TestLink 에서 처음으로 날아온 TC(TestCase)의 customField값이 CustomField_0001 이라고하면


<testcase  classname ="CustomField_0001"></testcase> 이 값을 찾게 됩니다. 그래서 만약에 해당 xml을 찾았을때


<failure>라는 태그가 없을시에는 pass로 처리를 하고 있을 경우 fail로 처리합니다.


그래서 원래는 Iterative Build Steps에서


테스트링크로 매번 넘어오는 테스트 케이스에 대한정보를 통해서 그때그때 실행하고 결과를 받아야 합니다.


하지만 저 같은 경우는 E2E테스트가 먼저 이루어진 후에 해당 결과를 넣어 줘야 하는 경우이기 때문에 


이렇게 작성되어있으며


아래 사진은 top.js (Client ) 에 있는 factory 라는 모듈에서 


factory.report() 를 호출했을때 의 모습입니다. 보시면  45건은 기본 페이지 렌더링시 하는 케이스들인데


이부분들에 대한 성공 실패와 우측엔 가렸지만 실패 메시지등이 들어있습니다.


End Point에서는 해당 리포트를 호출한 후 Node.js로 보내게 됩니다. 2번에서 따로 말씀드립니다.


셀레니엄 에서는 이부분을 






topqa.prototype.createJunitReport = async function(){
try{
let array = [];
const retVal = await this.driver.executeScript('return factory.report()');
makeJunitReport(retVal);
}
catch(err){
console.log(err);
}
}


Selenium에서는 executeScript 라는 API 가있습니다. 브라우저 인젝션을 할수 있도록 만들어진 API 인데요


위에 보시는 것처럼 factory.report() 를 호출후에 return 을 넣어 주면 retVal 에 해당 테스트결과를 받아 볼수 있습니다.


중간에 보시면


makeJunitReport(retVal);


라는 함수가있는데 이 함수의 내용은 이렇습니다.


const { makeJunitReport } = require('./topqaXmlBuilder');


이렇게 가져와서 사용하고 있으며 toqpaXmlBuilder의 원문은


/*

***** Pass Test Case
<testsuite>
<testcase classname="casebind" name="testName"></testcase>
</testsuite>

***** Fail Test Case
<testsuite>
<testcase classname="casebind" name="testName">
<failure type="test">Error Message</failure>
</testcase>
</testsuite>
*/

const builder = require('xmlbuilder');
const fs = require('fs');
const path = require('path');
const xmlHeader="<?xml version='1.0' encoding='UTF-8'?>";

// Create Test Dir
function makeDir(path){
fs.mkdirSync(path,{mode:0777});
}
// write file junit-testCase.xml
function makeJunitReportFile(xmlContent,path,testCase){
console.log(testCase);
let fd = fs.openSync(path+'/junit-'+testCase+'.xml','w');
fs.writeFileSync(fd,xmlContent,{encoding:"utf-8"});
}

function _isArray (array){
if((!!array && (array.length !==0 && typeof array.length!=="undefined"))){
        // [1] 의 배열도 return 이 되는데 이건 추후 생각
        return array;
}
    else{
        return false;
}
}
function makeJunitReport(testResultArray){
const array = _isArray(testResultArray);
if(array===false){return;}

console.log(array);
// // File Write for junit-*.xml
const dirPath = path.join(__dirname,'../chromeBuilding');
// ie firefox에 따라 다를수 있기 때문에 chromeBuilding -> Building으로 수정
!fs.existsSync(dirPath) ? makeDir(dirPath) : console.log('폴더 미생성');

testResultArray.reduce((acc,curr,index,arr) =>{
let junitObj = {
'testsuite': {
'testcase':{
'@classname':curr.tc,
'@name':curr.tc,
}
}
};
// fail Case
if(curr.result.toLowerCase()==='fail' || curr.result.toLowerCase()==='block'){
let failObj = {
'#text':curr.msg,
'@type':curr.result.toLowerCase() + 'Case'
};
junitObj.testsuite.testcase['failure'] = failObj
}
// xml Create
const junit = builder.create(junitObj,{encoding:'utf-8'});
// Create xml pretty change
const xmlContent = junit.end({pretty:true});
if(curr.tc.length>=1){
makeJunitReportFile(xmlContent,dirPath,curr.tc);
}
},0);
console.warn('test Result reporting Complete');
}
function api(){console.log('api')}

module.exports = {
makeJunitReport,
api
}


단순합니다. 저 위에 factory.report 에 있는 배열의 형태를 받아서 _isArray 를 통해 확인 후 테스트결과 폴더 생성 (없을시)


생성 후에 배열을 순회하면서 xmlBuilder형태의 Object를 만드는데 fail케이스인 경우는 failure를 넣어주기 위한 작업을 행합니다. 그리고 결과에 대한 junit 파일을 전부 만들어 놓고 종료 합니다.


파일이 다만들어진 상태이기 때문에


Iterative Build Steps 은 필요가 없고 역시 Single Build Steps 또한 필요가 없습니다.


그렇게 되면 바로 다음 단계인


Test Seeking로 넘어가게 되는데요 이부분에서 위에 만든 파일들을 찾으면서 test Case를 update하게됩니다.



로그를 보면(Jenkins ConsoleOut) 계속 케이스가 업데이트 되는 걸 확인 하실수 있습니다.


2. Selenium 이 EndPoint를 찍고나서 해당 함수가 Call 됐을때


2번째 End Point인데요 뭔가 다른거 같은데 차이를 쉽게 설명 드리자면


EndPoint Function 이 있습니다.


function endPoint(){ console.log('do anything');}


해당 함수는 어떤 버튼에 callback 으로 작성되어있을 건데  1번은 그 버튼을 찾아서 찍고난 후 이고 이번에 2번은


셀레니움이 찍어서 관련 함수가 callback 되었을때의 시점입니다.


해당 함수에서는 1번과 같이 factory.report()를 통한 결과를 가져온 후에


ajax 로 Node.js 서버에 보낼때 테스트결과와 해당 lib버전을 같이 보내는데 그 내용을 DBMS와 파일 2가지로 저장합니다.


해당 이유는 React 페이지에서 결과 추이 (전버전과 차이점 , 버그가 많은 버전, 변경된 기능 )


등을 볼수 있도록 하기 위함입니다.


감사합니다.


factory 모듈에 대해서는 따로 포스팅은 않았습니다.  뭔가 정형화된 패턴도 아니고 저만의 테스트 방식이라서 .. 


여기까지 Jenkins TestLink E2E 테스트 관련 이였습니다.


감사합니다.



+ Recent posts