2011-10-18 8 views
5

मेरी इंटर्नशिप के लिए, मुझे वेब-एप्लिकेशन का परीक्षण करने के लिए टेस्टएनजी और सेलेनियम का उपयोग करना होगा। लेकिन मुझे कोई समस्या है, कभी-कभी सेलेनियम या ब्राउज़र कुछ यादृच्छिक कारणों से काम नहीं कर रहा है, इसलिए एक कार्य परीक्षण को "असफल" के रूप में चिह्नित किया जाता है। इससे बचने के लिए, मैं एनोटेशन @Test(invocationCount = 4, successPercentage = 25) का उपयोग कर सकता हूं, फिर यदि परीक्षण एक बार सफल होता है, तो परीक्षण को "सफल" के रूप में चिह्नित किया जाता है, यह अच्छा है लेकिन समस्या यह है कि यह समाधान 4 से परीक्षण के लिए समय गुणा करता है, यह बहुत कुशल नहीं है ।टेस्टिंग और सेलेनियम परीक्षणों को अनुकूलित करने के लिए कैसे करें

परीक्षण के लिए समय कम करने के लिए मैं क्या कर सकता हूं, कुछ नियम लिखना है "यदि परीक्षण विफल हुआ, तो इस परीक्षण को फिर से शुरू करें (और केवल तभी परीक्षण विफल हो गया है), और यदि यह दूसरा, तीसरा, या चौथा बार, फिर इस परीक्षा को "सफल" के रूप में चिह्नित करें "तो मैं इन यादृच्छिक बग से बच सकता हूं। लेकिन मुझे यह नियम नहीं मिला है, मैंने देखा है कि हम एक श्रोता जोड़ सकते हैं, इसलिए हमारे पास "onTestFailure" नामक एक विधि है, इसलिए परीक्षण विफल होने पर मैं कुछ कर सकता हूं लेकिन मुझे नहीं पता कि पुनः- परीक्षण चलाओ।

मुझे testng-fail.xml भी मिला जहां सभी असफल परीक्षण सहेजे गए हैं, इसलिए हम इन परीक्षणों को दोबारा चलाने के लिए इस XML फ़ाइल को चला सकते हैं, लेकिन यह पिछले पहले रन से रिपोर्ट मिटा देगा, लेकिन मुझे बस यह चाहिए कि असफल परीक्षणों को "सफल" के रूप में चिह्नित किया जाता है यदि दूसरा रन सफल होता है। (मैंने जेनकींस में टेस्टएनजी/सेलेनियम एकीकृत किया है, इसलिए मेरे पास सभी परीक्षणों के साथ एक ग्राफ है, इसलिए यह विधि बहुत अनुकूल नहीं है, लेकिन यह विधि 4 से परीक्षण के लिए समय गुणा नहीं करती है और यह वही है जो मैं चाहता हूं)

तो यदि आपके पास ऐसा करने के लिए कोई सुराग है, तो यह बहुत अच्छा होगा।

+0

मैंने testng-fail.xml को 3 बार चलाने के लिए परीक्षण किया है, और फिर सभी परीक्षण काम कर रहे हैं, और इसमें बहुत समय नहीं लगता है। लेकिन जेनकींस के साथ, जब testng-fail.xml आखिरी बार चलाया जाता है, तो यह testng-result.xml को संपादित करेगा, इसलिए अब ग्राफ "1 टेस्ट रन, 1 सफल" इंगित करता है, क्योंकि आखिरी रन, testng ने केवल लॉन्च किया है यह परीक्षण जो 3 बार पहली बार विफल रहा। यह विधि सभी असफल परीक्षणों के साथ एक ग्राफ उत्पन्न करेगी, लेकिन सभी कामकाजी परीक्षण (परीक्षण जो तीसरे समय चल रहे हैं) को इंगित नहीं किया जाएगा, यह वही नहीं है जो मैं चाहता हूं ... कोई सुराग? – user1000499

उत्तर

4

आप जो भी खोज रहे हैं, उसे करने के लिए आप इरेट्रीएनलियर, एक श्रोता और एक कस्टम संवाददाता के संयोजन का उपयोग कर सकते हैं।

IRetryAnalyzer:

public class RetryAnalyzer implements IRetryAnalyzer { 
private int count = 0; 
// this number is actually twice the number 
// of retry attempts will allow due to the retry 
// method being called twice for each retry 
private int maxCount = 6; 
protected Logger log; 
private static Logger testbaseLog; 

static { 
    PropertyConfigurator.configure("test-config/log4j.properties"); 
    testbaseLog = Logger.getLogger("testbase.testng"); 
} 

public RetryAnalyzer() 
{ 
    testbaseLog.trace(" ModeledRetryAnalyzer constructor " + this.getClass().getName()); 
    log = Logger.getLogger("transcript.test"); 
} 

@Override 
public boolean retry(ITestResult result) { 
    testbaseLog.trace("running retry logic for '" 
      + result.getName() 
      + "' on class " + this.getClass().getName()); 
     if(count < maxCount) {      
       count++;          
       return true; 
     } 
     return false; 
} 
} 

RetryListener:

public class RetryTestListener extends TestListenerAdapter { 
private int count = 0; 
private int maxCount = 3; 

@Override 
public void onTestFailure(ITestResult result) {  
    Logger log = Logger.getLogger("transcript.test"); 
    Reporter.setCurrentTestResult(result); 

    if(result.getMethod().getRetryAnalyzer().retry(result)) {  
     count++; 
     result.setStatus(ITestResult.SKIP); 
     log.warn("Error in " + result.getName() + " with status " 
       + result.getStatus()+ " Retrying " + count + " of 3 times"); 
     log.info("Setting test run attempt status to Skipped");     
    } 
    else 
    { 
     count = 0; 
     log.error("Retry limit exceeded for " + result.getName()); 
    }  

    Reporter.setCurrentTestResult(null); 
} 

@Override 
public void onTestSuccess(ITestResult result) 
{ 
    count = 0; 
} 

हालांकि, वहाँ TestNG के भीतर एक बग वास्तव में का कारण बनता है कि के रूप में दोनों को छोड़ दिया और विफल परीक्षण के परिणाम के कुछ को सूचित किया जाना प्रतीत होता है। इसे रोकने के लिए, मैं सुझाव है कि आप को ओवरराइड जो कुछ भी रिपोर्टर आप का उपयोग करें और एक विधि के रूप में एक नीचे शामिल शामिल करना चाहते हैं:

private IResultMap removeIncorrectlyFailedTests(ITestContext test) 
{  
    List<ITestNGMethod> failsToRemove = new ArrayList<ITestNGMethod>(); 
    IResultMap returnValue = test.getFailedTests(); 

    for(ITestResult result : test.getFailedTests().getAllResults()) 
    { 
    long failedResultTime = result.getEndMillis();   

    for(ITestResult resultToCheck : test.getSkippedTests().getAllResults()) 
    { 
     if(failedResultTime == resultToCheck.getEndMillis()) 
     { 
      failsToRemove.add(resultToCheck.getMethod()); 
      break; 
     } 
    } 

    for(ITestResult resultToCheck : test.getPassedTests().getAllResults()) 
    { 
     if(failedResultTime == resultToCheck.getEndMillis()) 
     { 
      failsToRemove.add(resultToCheck.getMethod()); 
      break; 
     } 
    }   
    } 

    for(ITestNGMethod method : failsToRemove) 
    { 
     returnValue.removeResult(method); 
    } 

    return returnValue; 
} 

के बाद यह सब किया जाता है, आप .addListener का उपयोग कर का उपयोग करते हुए संवाददाता जोड़ सकते हैं और @Test एनोटेशन में retryAnalyzer निर्दिष्ट करें।

+0

एक बहुत धन्यवाद, यह बहुत अच्छी तरह से काम करता है, सही: डी – user1000499

4

आपको टेस्टफेलर पर लागू करने की आवश्यकता नहीं है। परीक्षण विफल होने पर टेस्टएनजी कॉल स्वचालित रूप से पुनः प्रयास करें। तो टेस्टफेलर पर ओवरराइड करने की कोई ज़रूरत नहीं है। यह पुनः प्रयास विधि 2 कॉल का कारण बनता है। मैंने नीचे के रूप में पुनः प्रयास किया।


private final Map rerunCountForTesCase = new HashMap(); 
    @Override 
    public boolean retry(ITestResult result) { 
       // here i have unique test case IDs for each of test method. 
       // So using utility method to get it. You can use method calss+name combination instead of testcaseid like me 
     String executingTestCaseID = ReportingUtilities.getTestCaseId(result); 
     if(rerunCountForTesCase.containsKey(executingTestCaseID)) 
     { 
      count = rerunCountForTesCase.get(executingTestCaseID); 
     } 
     else 
     { 
      rerunCountForTesCase.put(executingTestCaseID, 0); 
     } 
     if (count 0) 
       { 
        logInfo(tcID,"Sleeping for "+timeInSecs+ " secs before rerunning the testcase"); 
        Thread.sleep(timeInSecs * CommonFwBase.SHORTWAIT); 
       } 
      } catch (InterruptedException e) { 
       logError(null, e.getMessage()); 

      } 

      rerunCountForTesCase.put(executingTestCaseID, ++count); 
      return true; 
     } 
     return false; 

    } 

उपरोक्त थ्रेड में टेटफेलर के कार्यान्वयन के कारण दो बार बुलाया जाने वाला पुनः प्रयास करें। मैं असफल परिणामों को हटा देता हूं ताकि जब आप पुनः प्रयास करें तो यह नवीनतम परिणाम का उपयोग करता है। अन्यथा यदि आपके पास निर्भरता परीक्षण विधि है तो इसे छोड़ दिया जाता है (यद्यपि यह पहले परिणाम का उपयोग करने के बाद इसे पारित करने पर पुनः प्रयास करें)। रिपोर्टिंग करते समय आपको असफल प्रयासों को संभालना पड़ सकता है। आपको इस तरह पुनः प्रयास करने के बाद गुजरने वाले परीक्षणों को हटाना पड़ सकता है।

 m_ptests = suiteTestContext.getPassedTests(); 
     m_ftests = suiteTestContext.getFailedTests(); 
     m_stests = suiteTestContext.getSkippedTests(); 

     List<ITestNGMethod> methodsToRemove = new ArrayList<ITestNGMethod>(); 

     for(ITestResult failed_result : m_ftests.getAllResults()) 
     { 
      String failed_testName = failed_result.getMethod().getMethodName(); 
      String failingTest_className = failed_result.getClass().getName(); 
      for(ITestResult passed_result : m_ptests.getAllResults()) 
      { 
       String passing_testName = passed_result.getMethod().getMethodName(); 
       String passingTest_className = failed_result.getClass().getName(); 
       if(failed_testName.equals(passing_testName) && 
         passingTest_className.equals(failingTest_className))) 
       { 
        if(passed_result.getEndMillis() > failed_result.getEndMillis()) 
        { 

         methodsToRemove.add(failed_result.getMethod()); 
         break; 
        } 

       } 
      } 
     } 

     // remove the test that passed on retry 
     for(ITestNGMethod failedMethodToRemove : methodsToRemove) 
     { 
      m_ftests.removeResult(failedMethodToRemove); 
     } 

उम्मीद है कि यह बेहतर तरीके से पुनः प्रयास करने में मदद करता है।

0

अन्य उत्तरों "सही" तरीके हैं। "Quick'n'dirty" तरीके के लिए बस वास्तविक परीक्षण कोड को एक निजी विधि में ले जाएं। आपकी एनोटेटेड टेस्ट विधि में, कोशिश के साथ फॉर-लूप बनाएं ..जहां आप थ्रोबल (सभी त्रुटियों और अपवादों का सुपरक्लास) देखते हैं, वहां पकड़ लें। त्रुटि पर बस लूप जारी रखें या अंतिम त्रुटि फेंक दें, सफलता ब्रेक लूप पर।

नमूना कोड:

@Test 
public void testA() throws Throwable { 
    Throwable err = null; 
    for (int i=0; i<4; i++) { 
     try { 
      testImplementationA(); 
      return; 
     } catch (Throwable e) { 
      err = e; 
      continue; 
     } 
    } 
    throw err; 
} 

private void testImplementationA() 
{ 
    // put test code here 
} 

आमतौर पर है, हालांकि, यह बेहतर है परीक्षण है कि बेतरतीब ढंग से असफल नहीं लिखने के लिए। इस दृष्टिकोण का उपयोग करने के बारे में आपके पास इस बारे में जानकारी नहीं है कि कितने प्रयास विफल हुए हैं, जो सभी के बाद एक महत्वपूर्ण जानकारी है। मैं व्यक्तिगत रूप से विफलता पर जेनकींस पर पूरी टेस्ट क्लास/सूट फिर से चलाता हूं, और जांच करता हूं कि यह क्यों विफल रहा।

संबंधित मुद्दे