2013-10-08 9 views
5

Używam Selenium IDE do testowania internetowego systemu HR/SW.Jak mogę odczytać zmienne z puli danych z Selenium IDE?

Istnieje ekran, na którym można wprowadzić urlop dla pracowników.

Mam prawie 3000 pracowników.

Zbudowałem walizkę testową, która wprowadza wakacje dla jednego pracownika za pomocą zmiennych.

Jak mogę powtórzyć test dla wszystkich 3000 pracowników bez tworzenia przypadku testowego 3000 razy. Wykonanie tego będzie niemożliwe. Uwaga: Każdy pracownik ma różne dane dotyczące urlopu (Typ, data rozpoczęcia, Data zakończenia).

Czy istnieje sposób, w jaki mogę użyć pliku (Excel, ....), którego zmienna może użyć do odczytania jego danych?

Czy istnieje rozwiązanie dla mojej sprawy?

Będę bardzo wdzięczny, że ktokolwiek mógłby mi pomóc.

Dziękuję.

+0

Wygląda na to, że docierasz do końca tego, co potrafi IDE. – Arran

+0

NIE! Proszę!! Wszelkie prace dookoła? – 2ousy

Odpowiedz

0

Myślę, że musisz użyć Nie widzę twojego kodu, więc po prostu sprawdź this one dla selenium-ide loop Jeśli masz jakikolwiek problem, jeśli tak, skomentuj moją odpowiedź. Nie mogę wypowiedzieć się na twoje pytanie, ponieważ reputacja to za mało. Jeśli to możliwe, wpisz swój kod na swoje pytanie.

+0

Dziękuję, że był bardzo pomocny – 2ousy

5

Można użyć pliku XML jako danych wejściowych.

1) Najpierw trzeba dodać następujące rozszerzenia użytkowniczki:

sideflow.js - (http://51elliot.blogspot.com/2008/02/selenium-ide-goto.html - dodatkowo W tym artykule opisano sposób dodawania plików rozszerzeń użytkownik)

datadriven.js

include.js

W tej chwili nie mogę znaleźć linków, w których brałem ostatnie dwa, dlatego podam swój kod na końcu mojego postu. Kod jest pobierany z mojego katalogu roboczego. Po prostu wpisujesz kod do odpowiednich plików, a następnie dodajesz pliki do rozszerzenia użytkownika SelemiunIDE i używasz ich.

2) Utwórz test_data.xml pliku XML:

<testdata> 
    <test employee="1" type="1" startDate="01.01.2013" endDate="01.02.2013" /> 
    <test employee="2" type="1" startDate="01.02.2013" endDate="01.03.2013" /> 
    <test employee="3" type="1" startDate="01.03.2013" endDate="01.04.2013" /> 
... 
</testdata> 

3) w swoim kodzie testowym przypadek wykorzystania tak:

$ {DataPath} - pełną ścieżkę do katalogu z XML plików

<!--BEGIN LOOP--> 
<tr> 
    <td>loadTestData</td> 
    <td>file://${DataDir}/test_data.xml</td> 
    <td></td> 
</tr> 
<tr> 
    <td>while</td> 
    <td>!testdata.EOF()</td> 
    <td></td> 
</tr> 
<tr> 
    <td>nextTestData</td> 
    <td></td> 
    <td></td> 
</tr> 
<tr> 
    <td>echo</td> 
    <td>employee=${employee} type=${type} ...</td> 
    <td></td> 
</tr> 
... 
<!--END LOOP--> 
<tr> 
    <td>endWhile</td> 
    <td></td> 
    <td></td> 
</tr> 

Używane rozszerzenia użytkownika:

zawierają.js

/** 
* Original Developer: Jerry Qian([email protected]) 
* Modified By: John Witchel ([email protected]) 
* include extension for Selenium-IDE edition 
* refer to includeCommand_2.1.3 for Selenium-Core edition 
* @version 1.3 
* 
*/ 
function IDEIncludeCommand() {} 

IDEIncludeCommand.LOG_PREFIX = "IDEIncludeCommand: "; 
IDEIncludeCommand.BEGIN_TEMPLATE = "begin$Template$"; 
IDEIncludeCommand.END_TEMPLATE = "end$Template$"; 
IDEIncludeCommand.VERSION = "1.1"; 

IDEIncludeCommand.prototype.prepareTestCaseAsText = function(responseAsText, paramsArray) { 
    /** 
    * Prepare the HTML to be included in as text into the current testcase-HTML 
    * Strip all but the testrows (tr) 
    * Stripped will be: 
    * - whitespace (also new lines and tabs, so be careful wirt parameters relying on this), 
    * - comments (xml comments)     
    * Replace variable according to include-parameters 
    * note: the include-variables are replaced literally. selenium does it at execution time 
    * also note: all selenium-variables are available to the included commands, so mostly no include-parameters are necessary 
    * 
    * @param responseAsText table to be included as text (string) 
    * @return testRows array of tr elements (as string!) containing the commands to be included 
    * 
    * TODO: 
    * - selenium already can handle testcase-html. use selenium methods or functions instead 
    * - find better name for requester 
    */ 
    // removing new lines, carret return and tabs from response in order to work with regexp 
    var pageText = responseAsText.replace(/\r|\n|\t/g,""); 
    // remove comments 
    // begin comment, not a dash or if it's a dash it may not be followed by -> repeated, end comment 
    pageText = pageText.replace(/<!--(?:[^-]|-(?!->))*-->/g,""); 
    // find the content of the test table = <[spaces]table[char but not >]>....< /[spaces]table[chars but not >]> 
    var testText = pageText.match(/<\s*table[^>]*>(.*)<\/\s*table[^>]*>/i)[1]; 

    // Replace <td></td> with <td>&nbsp;</td> for iE - credits Chris Astall 
    // rz: somehow in my IE 7 this is not needed but is not bad as well 
    testText = testText.replace(/<\s*td[^>]*>\s*<\s*\/td[^>]*>/ig,"<td></td>");// jq: no space 

    // replace vars with their values in testText 
    for (var k = 0 ; k < paramsArray.length ; k++) { 
     var pair = paramsArray[k]; 
     testText = testText.replace(pair[0],pair[1]); 
    } 

    // removes all < /tr> 
    // in order to split on < tr> 
    testText = testText.replace(/<\/\s*tr[^>]*>/ig,""); 
    // split on <tr> 
    var testRows = testText.split(/<\s*tr[^>]*>/i); 
    return testRows; 
}; 

IDEIncludeCommand.prototype.getIncludeDocumentBySynchronRequest = function(includeUrl) { 
    /** 
    * Prepare and do the XMLHttp Request synchronous as selenium should not continue execution meanwhile 
    * 
    * note: the XMLHttp requester is returned (instead of e.g. its text) to let the caller decide to use xml or text 
    * 
    * selenium-dependency: uses extended String from htmlutils 
    * 
    * TODO use Ajax from prototype like this: 
    * var sjaxRequest = new Ajax.Request(url, {asynchronous:false}); 
    * there is discussion about getting rid of prototype.js in developer forum. 
    * the ajax impl in xmlutils.js is not active by default in 0.8.2 
    * 
    * @param includeUrl URI to the include-document (document has to be from the same domain) 
    * @return XMLHttp requester after receiving the response 
    */ 
    var url = this.prepareUrl(includeUrl); 
    // the xml http requester to fetch the page to include 
    var requester = this.newXMLHttpRequest(); 
    if (!requester) { 
     throw new Error("XMLHttp requester object not initialized"); 
    } 
    requester.open("GET", url, false); // synchron mode ! (we don't want selenium to go ahead) 
    try { 
     requester.send(null); 
    } catch(e) { 
     throw new Error("Error while fetching url '" + url + "' details: " + e); 
    } 
    if (requester.status != 200 && requester.status !== 0) { 
     throw new Error("Error while fetching " + url + " server response has status = " + requester.status + ", " + requester.statusText); 
    } 
    return requester; 
}; 

IDEIncludeCommand.prototype.prepareUrl = function(includeUrl) { 
    /** Construct absolute URL to get include document 
    * using selenium-core handling of urls (see absolutify in htmlutils.js) 
    */ 
    var prepareUrl; 
    // htmlSuite mode of SRC? TODO is there a better way to decide whether in SRC mode? 
    if (window.location.href.indexOf("selenium-server") >= 0) { 
     LOG.debug(IDEIncludeCommand.LOG_PREFIX + "we seem to run in SRC, do we?"); 
     preparedUrl = absolutify(includeUrl, htmlTestRunner.controlPanel.getTestSuiteName()); 
    } else { 
     preparedUrl = absolutify(includeUrl, selenium.browserbot.baseUrl); 
    } 
    LOG.debug(IDEIncludeCommand.LOG_PREFIX + "using url to get include '" + preparedUrl + "'"); 
    return preparedUrl; 
}; 

IDEIncludeCommand.prototype.newXMLHttpRequest = function() { 
    // TODO should be replaced by impl. in prototype.js or xmlextras.js 
    //  but: there is discussion of getting rid of prototype.js 
    //  and: currently xmlextras.js is not activated in testrunner of 0.8.2 release 
    var requester = 0; 
    var exception = ''; 
    // see http://developer.apple.com/internet/webcontent/xmlhttpreq.html 
    // changed order of native and activeX to get it working with native 
    // xmlhttp in IE 7. credits dhwang 
    try { 
     // for IE/ActiveX 
     if(window.ActiveXObject) { 
      try { 
       requester = new ActiveXObject("Msxml2.XMLHTTP"); 
      } 
      catch(e) { 
       requester = new ActiveXObject("Microsoft.XMLHTTP"); 
      } 
     } 
     // Native XMLHttp 
     else if(window.XMLHttpRequest) { 
      requester = new XMLHttpRequest(); 
     } 
    } 
    catch(e) { 
     throw new Error("Your browser has to support XMLHttpRequest in order to use include \n" + e); 
    } 
    return requester; 
}; 

IDEIncludeCommand.prototype.splitParamStrIntoVariables = function(paramString) { 
    /** 
    * Split include Parameters-String into an 2-dim array containing Variable-Name and -Value 
    * 
    * selenium-dependency: uses extended String from htmlutils 
    * 
    * TODO: write jsunit tests - this could be easy (if there were not the new RegExp) 
    * 
    * @param includeParameters string the parameters from include call 
    * @return new 2-dim Array containing regExpName (to find a matching variablename) and value to be substituted for 
    */ 
    var newParamsArray = new Array(); 
    // paramString shall contains a list of var_name=value 
    var paramListPattern = /([^=,]+=[^=,]*,)*([^=,]+=[^=,]*)/; 
    if (! paramString || paramString === "") { 
     return newParamsArray; 
    } else if (paramString.match(paramListPattern)) { 
     // parse parameters to fill newParamsArray 
     var pairs = paramString.split(","); 
     for (var i = 0 ; i < pairs.length ; i++) { 
      var pair = pairs[i]; 
      var nameValue = pair.split("="); 
      //rz: use String.trim from htmlutils.js of selenium to get rid of whitespace in variable-name(s) 
      var trimmedNameValue = new String(nameValue[0]).trim(); 
      // the pattern to substitute is ${var_name} 
      var regExpName = new RegExp("\\$\\{" + trimmedNameValue + "\\}", "g"); 

      if (nameValue.length < 3) { 
       newParamsArray.push(new Array(regExpName,nameValue[1])); 
      } else { 
       var varValue = new String(nameValue[1]); 
       for (var j = 2; j < nameValue.length; j++) { 
        varValue=varValue.concat("="+nameValue[j]); 
       } 
       newParamsArray.push(new Array(regExpName,varValue)); 
      } 
     } 
    } else { 
     throw new Error("Bad format for parameters list : '" + paramString + "'"); 
    } 
    return newParamsArray; 
}; 

IDEIncludeCommand.prototype.doInclude = function(locator, paramString) { 
    // Rewrite logic for Selenium IDE by Jerry Qian 
    var currentSelHtmlTestcase = testCase; 

    var includeCmdRow = testCase.debugContext.currentCommand(); 

    if (!includeCmdRow) { 
     throw new Error("IDEIncludeCommand: failed to find include-row in source testtable"); 
    } 

    var paramsArray = this.splitParamStrIntoVariables(paramString); 

    var inclDoc = this.getIncludeDocumentBySynchronRequest(locator); 

    // Get an array of commands from the include text with all whitespace stripped 
    var includedTestCaseHtml = this.prepareTestCaseAsText(inclDoc.responseText, paramsArray); 


    this.injectIncludeTestCommands(locator,includeCmdRow,includedTestCaseHtml); 
}; 

IDEIncludeCommand.prototype.injectIncludeTestCommands = function(locator,includeCmdRow, testRows) { 
    // Rewrite logic for Selenium IDE by Jerry Qian 
    var newCommands = new Array(); 
    // skip first element as it is empty or <tbody> 
    for (var i = 1 ; i < testRows.length; i++) { 
      if(i == 1){// add BEGIN-END block 
      var beginCommand = new Command(IDEIncludeCommand.BEGIN_TEMPLATE,locator,"");  
      newCommands.push(beginCommand); 
      } 

      var newText = testRows[i]; 
      if(newText.match(/<\s*td.*colspan=.*>(.*)<\/\s*td[^>]*>/i)){//delete comment step 
      continue; 
      } 

      // removes all < /td> 
      // in order to split on <td> 
      newText = newText.replace(/<\/\s*td[^>]*>\s*<\/\s*tbody[^>]*>/ig,""); //remove </tbody>first 
      newText = newText.replace(/<\/\s*td[^>]*>/ig,""); 
      var newCols = newText.split(/<\s*td[^>]*>/i); 
      var new_cmd,new_target,new_value; 

      for (var j = 1 ; j < newCols.length; j++) {//skip 0 
      if(j == 1) { 
       new_cmd = newCols[j].replace(/\s/g,"");//trim \s 
      }else if(j == 2) { 
       new_target = newCols[j].replace(/\s+$/g,"");//trim end \s 
      }else if(j == 3) { 
       new_value = newCols[j].replace(/\s+$/g,"");//trim end \s 
      } 
      } 

      var newCommand = new Command(new_cmd,new_target,new_value); 
      newCommands.push(newCommand); //correct all steps 
    } 
    var endCommand = new Command(IDEIncludeCommand.END_TEMPLATE,locator,"");  
    newCommands.push(endCommand);//add BEGIN-END block 


    var cmsBefore = testCase.commands.slice(0,testCase.debugContext.debugIndex + 1);  
    var cmdsBehind = testCase.commands.slice(testCase.debugContext.debugIndex + 1, testCase.commands.length);  
    testCase.commands = cmsBefore.concat(newCommands).concat(cmdsBehind);//Injection 

    // Don't inject if it appears the injection has already been done 
    // (i.e., if the next command is the BEGIN). 
    if (testCase.commands.length <= testCase.debugContext.debugIndex+1 
     || beginCommand.toString() != testCase.commands[testCase.debugContext.debugIndex+1].toString()) 
    { 
     // The include command cannot be the last command in the TestCase, or else 
     // the de-injection code in doEnd$Template$ will cause an error. So we'll 
     // add a simple echo if it is the last. 
     if (testCase.commands.length == testCase.debugContext.debugIndex+1) 
     { 
      // Using concat instead of push so that we don't trigger the TestCase's set-modified flag. 
      testCase.commands = testCase.commands.concat(new Command("echo", "The include command cannot be the last line in a TestCase, so this command was added. It can be left in place or removed, as desired.", "The include command cannot be the last line in a TestCase, so this command was added. It can be left in place or removed, as desired.")); 
     } 

     // This is original code. 
     var cmsBefore = testCase.commands.slice(0,testCase.debugContext.debugIndex + 1); 
     var cmdsBehind = testCase.commands.slice(testCase.debugContext.debugIndex + 1, testCase.commands.length); 
     testCase.commands = cmsBefore.concat(newCommands).concat(cmdsBehind);//Injection 
    } 
}; 

Selenium.prototype.doInclude = function(locator, paramString) { 
    LOG.debug(IDEIncludeCommand.LOG_PREFIX + "Version " + IDEIncludeCommand.VERSION); 
    var ideIncludeCommand = new IDEIncludeCommand(); 
    ideIncludeCommand.doInclude(locator, paramString); 

    // If goto scripts exist then reindex the labels. goto_sel_ide.js creates an array of labels when the 
    // script is initialized but an included file's labels are not part of that initial read, so this function 
    // re-initializes that array with the included files labels (if any). If goto_sel.ide.js is not included 
    // it's ignored. 
    try { 
     this.initialiseLabels(); 
    } 
    catch (e) { 
     LOG.debug("Goto Script not used."); 
    } 

}; 

// Array to hold the starting position of the Begin$Template$ marker. Pushing and popping the position onto an array 
// allows us to correctly handle nested includes during clean up. 
var beginTemplateIndex = new Array(); 

// Mark the beginning of the include 
Selenium.prototype.doBegin$Template$ = function(locator){ 
    LOG.info("Begin Template " + locator + " at position " + testCase.debugContext.debugIndex); 
    // Add the current position to the tail of the beginTemplateIndex 
    beginTemplateIndex.push(testCase.debugContext.debugIndex); 
}; 

// Clean up everything between the closest Begin$Template$ and this $End$Template$, and pop the position off the array. 
Selenium.prototype.doEnd$Template$ = function(locator){ 

    // Remove the last Begin$Template$ from the tail of the beginTemplateIndex 
    var currentBeginTemplateIndex = beginTemplateIndex.pop(); 
    LOG.info("End Template " + locator + " at position " + currentBeginTemplateIndex); 

    // Delete the commands that we injected in injectIncludeTestCommands. 
    testCase.commands = 
     testCase.commands.slice(0,currentBeginTemplateIndex).concat(
      testCase.commands.slice(testCase.debugContext.debugIndex+1, testCase.commands.length)); 

    // Set the current command to the next one after the injected block. 
    testCase.debugContext.debugIndex = currentBeginTemplateIndex-1; 

    //Must refresh to syncup UI 
    editor.view.refresh(); 
}; 

datadriven.js

/************************************ DATADRIVEN EXTENSION START ********************************************/ 
/* 
NAME: 
    datadriven 

    Licensed under Apache License v2 
    http://www.apache.org/licenses/LICENSE-2.0 

PURPOSE: 
    Basic data driven testing. 

    Full documentation at http://wiki.openqa.org/display/SEL/datadriven 


EXAMPLE USE: 
    The structure of your data driven test case will be; 
    ------------------------------------------- 
    COMMAND  |TARGET   |VALUE 
    ------------------------------------------- 
    loadTestData |<file path>  | 
    while   |!testdata.EOF() | 
    testcommand1 |    | 
    testcommand...|    | 
    testcommandn |    | 
    endWhile  |    | 
    ------------------------------------------- 

AUTHOR: 
    Jonathan McBrien 
    [email protected] 
    2008-10-22: v0.1: Initial version. 
    2009-01-16: v0.2: Updated for Firefox 3. 
       xmlTestData.prototype.load now uses the include extension's getIncludeDocumentBySynchronRequest method for better portability. 
       (Why reinvent the wheel? :) - with appreciation to the include extension's authors.) 
*/ 

XML.serialize = function(node) { 
    if (typeof XMLSerializer != "undefined") 
     return (new XMLSerializer()).serializeToString(node) ; 
    else if (node.xml) return node.xml; 
    else throw "XML.serialize is not supported or can't serialize " + node; 
} 

function xmlTestData() { 
    this.xmlDoc = null; 
    this.testdata = null; 
    this.index = null; 
} 


xmlTestData.prototype.load = function(xmlloc) { 
    loader = new IDEIncludeCommand(); 
    var xmlHttpReq = loader.getIncludeDocumentBySynchronRequest(xmlloc); 
    this.xmlDoc = xmlHttpReq.responseXML; 

    this.index = 0; 
    this.testdata = this.xmlDoc.getElementsByTagName("test"); 

    if (this.testdata == null || this.testdata.length == 0) { 
     throw new Error("Test data couldn't be loaded or test data was empty."); 
    } 
} 

xmlTestData.prototype.EOF = function() { 
    if (this.index != null && this.index < this.testdata.length) return false; 
    return true; 
} 

xmlTestData.prototype.more = function() { 
    return !this.EOF(); 
} 

xmlTestData.prototype.next = function() { 
    if (this.EOF()) { 
     LOG.error("No test data."); 
     return; 
    } 

    LOG.info(XML.serialize(this.testdata[this.index])); // Log should anything go wrong while testing with this data. 

    if (this.testdata[this.index].attributes.length != this.testdata[0].attributes.length) { 
     LOG.error("Inconsistent attribute length in test data."); 
     return; 
    } 

    for (i=0; i<this.testdata[this.index].attributes.length; i++){ 
     if (null == this.testdata[0].getAttribute(this.testdata[this.index].attributes[i].nodeName)) { 
      LOG.error("Inconsistent attribute names in test data."); 
      return; 
     } 

     selenium.doStore(this.testdata[this.index].attributes[i].nodeValue, this.testdata[this.index].attributes[i].nodeName); 
    } 

    this.index++; 
} 

Selenium.prototype.testdata = null; 

Selenium.prototype.doLoadTestData = function(xmlloc) { 
    testdata = new xmlTestData(); 
    testdata.load(xmlloc); 
}; 

Selenium.prototype.doNextTestData = function() { 
    testdata.next(); 
}; 

/************************************ DATADRIVEN EXTENSION END **********************************************/ 
+0

faktycznie obecne SelBlocks obejmują to wszystko .. – Dee

1

Można również sprawdzić to bardzo miły wpis na blogu: http://seleniumworks.blogspot.com/2014/01/selenium-ide-data-driven.html

Daje to wyjaśnienie, w jaki sposób korzystać z potrzebnych wtyczek i gdzie aby pobrać je z. To zadziałało idealnie dla mnie.

Ta odpowiedź ma prawie takie samo podejście jak ta dostarczona przez @Yevgen Ulyanenkov, ponieważ użyłem jego odpowiedzi, aby znaleźć powyższy artykuł. Ale ma trochę więcej googlowania, co przyniesie nadzieję komuś.

2

obecne rozwiązanie jest SelBlocks komponent, który pozwala na wykonywanie cykli w zależności od zestawu danych w formacie XML

ForXML | XMLFileName.XML 
... test case steps 
EndForXML 

XML powinien mieć specyficzną strukturę

<testdata> 
    <vars storedVariable1="xxxxx" storedVariable2="yyyyy" .. storedVariableN="zzzzz" /> 
    .. other record(s) 
</testdata> 

Każdy przechowywany zmienny Vill być dostępny w przypadku testowym jako ${storedVariableN}.

Można produkować XML przez MS Excel lub LibreOffice za pomocą formuł jak ten i skopiować go do całej tabeli:

="<vars "& 
" "&$A$1&"="""&A2&""" "& 
" "&$B$1&"="""&B2&""" "& 
.. 
" "&$X$1&"="""&X2&""" "& 
"/>") 

XML można łatwo copypasted po każdej zmianie zestawu danych.

Selblocks zawiera ciąg dalszy, datadriven, goto, loop i inne rozszerzenia wymienione w poprzednich odpowiedziach. Można korzystać z innych funkcjonalności Selblocks jako skoków warunkowych, warunków, spróbuj złapać-bloki, funkcje, itd. Zobacz pełne odniesienie tutaj: http://refactoror.wikia.com/wiki/Selblocks_Reference

Strzeż z nowym Selen 3 uwalniania i Sel podstawowej nieobecności nie jest gwarantowana, testy z dodatkiem Selblock będą działały w przyszłych wersjach firefox.

Powiązane problemy