2015-03-17 12 views
5

के माध्यम से विफल परीक्षण परीक्षण परिणाम TestNG retrying failed tests doesn't output the correct test results पर पोस्ट किए गए समाधान के समान, मैं फिनिश (ITestContext संदर्भ) के दौरान एक परीक्षण श्रोता का उपयोग करके एक (डुप्लिकेट) परीक्षण परिणाम निकालने का प्रयास कर रहा हूं।हटाएं (डुप्लिकेट) परीक्षण श्रोता

हालांकि context.getFailedTests() के साथ परिणाम को हटाने के बाद। निष्कासन परिणाम (परिणाम) ठीक काम करता प्रतीत होता है (परिणाम वास्तव में हटा दिया जाता है), ऐसा लगता है कि "कुछ अन्य स्थान" जहां परिणाम कारण से खींचे जा रहे हैं निर्माण अभी भी विफल रहता है।

यह भी ध्यान दें कि जब मैं ऊपर दिए गए आलेख से नमूना परीक्षण चलाता हूं (जिसमें एक डुप्लिकेट विफलता को हटाया जाता है और एक उत्तीर्ण परीक्षण होता है), तो मुझे "परीक्षण परिणाम" (अपेक्षा के अनुसार साफ़ नहीं किया गया) में अंतर मिलता है। "सूट परिणाम" (अपेक्षित के रूप में डुप्लिकेट विफलता हटा दी गई)।

और, रिपोर्टिंग को विफल करने के लिए परिणामों को खींचने के लिए रिपोर्ट कहां से खींच रही है? या यह सिर्फ यह है कि मैं असफल परीक्षणों की सफाई करने से पहले परिणाम खींच रहा हूं ...?

=============================================== 
    Default test 
    Tests run: 3, Failures: 2, Skips: 0 
=============================================== 

=============================================== 
Default suite 
Total tests run: 2, Failures: 1, Skips: 0 
=============================================== 

संपादित करें: बस स्पष्ट करने के लिए, हम Maven के साथ उन लोगों परीक्षण चल रहे हैं, और वे अपने हैं, इसलिए हम उन्हें फेल सेफ प्लगइन के साथ चलाते हैं। समस्या यह है कि भले ही यह प्रतीत होता है कि परीक्षण हटा दिए जाते हैं, एमवीएन सत्यापित अभी भी बिल्ड में विफल रहता है क्योंकि यह असफलताओं को बनाने के बावजूद पाया जाता है।

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

रेट्रीएनलर के बारे में: मैं रेट्रीएनलियर अच्छा/सर्वोत्तम अभ्यास का उपयोग करने पर विचार नहीं करता, लेकिन यदि आप खुद को ऐसी स्थिति में पाते हैं जहां आपको समस्या को हल करने की आवश्यकता है, उदा। आपने एक परीक्षण सूट विरासत में लिया है जो RetryAnalyzer पर निर्भर है, आपको यह उपयोगी मिल सकता है।

ListenerApadter:

public class MyTestListenerAdapter extends TestListenerAdapter { 
    @Override 
    public void onTestFailure(ITestResult result) { 
     if (result.getMethod().getRetryAnalyzer() != null) { 
      MyRetryAnalyzer retryAnalyzer = (MyRetryAnalyzer)result.getMethod().getRetryAnalyzer(); 

      if(retryAnalyzer.isRetryAvailable()) { 
       result.setStatus(ITestResult.SKIP); 
      } else { 
       result.setStatus(ITestResult.FAILURE); 
      } 
      Reporter.setCurrentTestResult(result); 
     } 
    } 

    @Overrride 
    public void onFinish(ITestContext context) { 
    Iterator<ITestResult> failedTestCases =context.getFailedTests().getAllResults().iterator(); 
    while (failedTestCases.hasNext()) { 
     System.out.println("failedTestCases"); 
     ITestResult failedTestCase = failedTestCases.next(); 
     ITestNGMethod method = failedTestCase.getMethod(); 
     if (context.getFailedTests().getResults(method).size() > 1) { 
      System.out.println("failed test case remove as dup:" + failedTestCase.getTestClass().toString()); 
      failedTestCases.remove(); 
     } else { 

      if (context.getPassedTests().getResults(method).size() > 0) { 
       System.out.println("failed test case remove as pass retry:" + failedTestCase.getTestClass().toString()); 
       failedTestCases.remove(); 
      } 
     } 
    } 
    } 
} 

RetryAnalizer:

+0

क्या आपको इस समस्या का समाधान मिला है? – MrSpock

+0

हम कुछ "उपयोग करने योग्य" को समझते हैं, हालांकि मैं अंततः जो चाहता था वह नहीं। मैं कोड को साफ करने और इसे पोस्ट करने के लिए अगले कुछ दिनों में कुछ समय खोजने का प्रयास करूंगा। – mac

+0

अपना समाधान देखने के लिए उत्सुक! – MrSpock

उत्तर

2

इस कोड का उपयोग का प्रयास करें

public class MyRetryAnalyzer implements IRetryAnalyzer { 
    private static int MAX_RETRY_COUNT = 3; 

    AtomicInteger count = new AtomicInteger(MAX_RETRY_COUNT); 

    public boolean isRetryAvailable() { 
     return (count.intValue() > 0); 
    } 

    @Override 
    public boolean retry(ITestResult result) { 
     boolean retry = false; 
     if (isRetryAvailable()) { 
      System.out.println("Going to retry test case: " + result.getMethod() + ", " + (MAX_RETRY_COUNT - count.intValue() + 1) + " out of " + MAX_RETRY_COUNT); 
      retry = true; 
      count.decrementAndGet(); 
     } 
     return retry; 
    } 
} 

pom.xml -> अचूक विन्यास:

यह वह जगह है जहां आपको "ओवरराइट" निश्चित फ़ायरनर कॉन्फ़िगर करना चाहिए जिसमें उनके स्वयं के काउंटर हैं।

<plugin> 
    <groupId>org.apache.maven.plugins</groupId> 
    <artifactId>maven-surefire-plugin</artifactId> 
    <version>2.18.1</version> 
    <configuration> 
    <suiteXmlFiles><suiteXmlFile>${basedir}/testng.xml</suiteXmlFile></suiteXmlFiles> 
<properties> 
    <property> 
    <name>listener</name> 
    <value>Utils.MyTestListenerAdapter,Utils.MyRetryAnalizer</value> 
    </property> 
</properties> 

+0

सत्यापित करते हैं, तो मुझे साफ करना बेकार होगा, लेकिन मुझे डर है कि यह विश्वसनीय रूप से काम नहीं करेगा। सबसे पहले, हम स्किप्स के साथ टेस्ट रनों को सफल नहीं मानते हैं। दूसरा, समाधान थोड़ा जोखिम भरा प्रतीत होता है, क्योंकि प्रत्येक रेट्रीएनलर उस प्रकार का नहीं हो सकता है (शायद छोटी परियोजनाओं में, लेकिन कई मैवेन प्रोजेक्ट्स में फैले बड़ी परियोजनाओं में नहीं)। Reporter.setCurrentStatus() के साथ विचार हालांकि दिलचस्प लगता है। साथ ही, एक तरफ ध्यान दें: इस प्रकार का RetryAnalyzer समाधान पैरामीटर/डेटा प्रदाताओं के साथ परीक्षण विधियों के लिए ठीक से काम नहीं करता है। – mac

+0

@ एमएसी अपडेटेड: जिस तरह से आपको छोड़ने की आवश्यकता है उसे संभालने के लिए "ऑनफिनिश" में कोड जोड़ें और सामान्य रूप से असफल परीक्षण – Morvader

+0

, मुझे लगता है कि अब आपके कोड में कुछ विरोधाभास हैं क्योंकि आप परीक्षण को स्किप के रूप में चिह्नित कर रहे हैं, लेकिन फिर आप ' बाद में असफलताओं को फिर से हटा रहा है। साथ ही, मुझे लगता है कि आप अपने पूरे भाग को केवल टेस्टफेलर() में रेट्रीएनलियर में ही ले जा सकते हैं, और फिर आपको जोखिम भरा कास्टिंग भी नहीं करना पड़ेगा। आम तौर पर, मुझे लगता है कि यह अभी भी वही दृष्टिकोण है जैसा कि मैंने शीर्ष पर पोस्ट किया था। मुद्दा यह है कि जब आप यह सब करते हैं, तो मेरा मानना ​​है कि एमवीएन सत्यापित चरण (क्योंकि हम असल में असफल होने के साथ आईटी के लिए ऐसा कर रहे हैं) अभी भी – mac

0

मैं एक समाधान एक सूट श्रोता का उपयोग करता है के लिए जा रहा समाप्त हो गया।

समाधान टेस्टएनजी/आपके परीक्षण कंसोल पर लॉग इन करने के लिए पूरी तरह से साफ़ नहीं हो सकता है, लेकिन यदि आप टेस्टएनजी जेनकींस प्लगइन का उपयोग करते हैं, और प्रत्येक परीक्षण पर पहले विफलता होती है, और फिर सफलता होती है, तो परीक्षण रन समाप्त होता है हरा, जो मुझे लगता है वह सबसे महत्वपूर्ण बात है।

और हाँ, हम एमवीएन एकीकरण-परीक्षण (एमवीएन सत्यापित नहीं) चलाते हैं और टेस्टएनजी प्लगइन को पास/असफल के साथ सौदा करते हैं। The solution is quite similar/builds on what was posted here

public static int cleanUpDuplicateFailures(ITestContext testContext) { 
    final String testContextName = testContext.getName(); 
    int removedFailures = 0; 

    LOG.info("Cleaning up failures in test context '" + testContextName + "' ..."); 
    final Set<ITestResult> failedTests = testContext.getFailedTests().getAllResults(); 
    if (failedTests.isEmpty()) { 
     LOG.info("There are no failures in test context '" + testContextName + "'\n"); 
    } else { 
     // collect all id's from passed test 
     final Set<Integer> passedTestIds = new HashSet<>(); 
     final Set<ITestResult> passedTests = testContext.getPassedTests().getAllResults(); 
     LOG.info("Analyzing " + passedTests.size() + " passed test(s)"); 
     for (ITestResult result : passedTests) { 
      final int testId = TestListenerUtil.getId(result); 
      passedTestIds.add(testId); 
      LOG.info(" Passed test " + TestListenerUtil.getName(result) + ": #" + testId + " @ " 
        + getStartTime(result)); 
     } 

     // check which failed test results should be removed 
     final List<Integer> resultsToBeRemoved = new ArrayList<>(); 
     final Set<Integer> failedTestIds = new HashSet<>(); 

     LOG.info("Analyzing " + failedTests.size() + " failed test(s)"); 
     for (ITestResult result : failedTests) { 
      final int testId = TestListenerUtil.getId(result); 
      final String name = TestListenerUtil.getName(result); 

      // if we saw this test pass or fail before we mark the result for deletion 
      if (failedTestIds.contains(testId) || passedTestIds.contains(testId)) { 
       LOG.info(" Adding test " + name + " to be removed: #" + testId + " @ " + getStartTime(result)); 
       resultsToBeRemoved.add(testId); 
      } else { 
       LOG.info(" Remembering failed test " + name + ": #" + testId + " @ " + getStartTime(result)); 
       failedTestIds.add(testId); 
      } 
     } 

     // finally delete all duplicate failures (if any) 
     final int duplicateFailures = resultsToBeRemoved.size(); 
     if (duplicateFailures > 0) { 
      LOG.info("Cleaning up failed tests (expecting to remove " + resultsToBeRemoved.size() 
        + " result(s)) ..."); 
      for (ITestResult result : testContext.getFailedTests().getAllResults()) { 
       final int testId = TestListenerUtil.getId(result); 
       final String info = TestListenerUtil.getName(result) + ": #" + testId + " @ " 
         + getStartTime(result); 
       if (resultsToBeRemoved.contains(testId)) { 
        LOG.info(" Removing failed test result " + info); 
        testContext.getFailedTests().removeResult(result); 
        resultsToBeRemoved.remove((Integer) testId); 
        removedFailures++; 
       } else { 
        LOG.info(" Not removing failed test result " + info); 
       } 
      } 
     } 

     if (removedFailures == duplicateFailures) { 
      LOG.info("Removed " + removedFailures + " failed test result(s) in '" + testContextName + "'\n"); 
     } else { 
      LOG.warn("Removed " + removedFailures + " failed test result(s) in '" + testContextName 
        + "' (expected to remove " + duplicateFailures + ")\n"); 
     } 
    } 

    return removedFailures; 
} 
उन दो अतिरिक्त utils तरीकों के साथ

:

import java.util.Map; 

import org.apache.logging.log4j.LogManager; 
import org.apache.logging.log4j.Logger; 
import org.testng.ISuite; 
import org.testng.ISuiteListener; 
import org.testng.ISuiteResult; 
import org.testng.ITestContext; 

/** 
* {@link ISuiteListener} implementation to clean up duplicate test results caused by retrying tests using the 
* {@link RetryAnalyzer} 
*/ 
public class SuiteResultListener implements ISuiteListener { 

    private static final Logger LOG = LogManager.getLogger(); 

    @Override 
    public void onStart(ISuite suite) { 
    } 

    @Override 
    public void onFinish(ISuite suite) { 
     LOG.info("Cleaning up duplicate test failures in suite '" + suite.getName() + "' ..."); 
     final Map<String, ISuiteResult> results = suite.getResults(); 
     int removedFailures = 0; 
     for (ISuiteResult result : results.values()) { 
      final ITestContext testContext = result.getTestContext(); 

      removedFailures += TestListenerUtil.cleanUpDuplicateFailures(testContext); 
     } 

     LOG.info("Removed " + removedFailures + " duplicate test failure(s) from suite '" + suite.getName() + "'"); 
    } 
} 

और यहाँ जादू कि TestListenerUtil वर्ग में क्या होता है,

public static String getName(ITestResult result) { 
    final List<String> parameters = new ArrayList<>(); 
    if (result.getParameters() != null) { 
     for (Object parameter : result.getParameters()) { 
      if (parameter instanceof TestResult && ((TestResult) parameter).getStatus() < 0) { 
       // TestResult.toString() will explode with status < 0, can't use the toString() method 
       parameters.add(parameter.getClass().getName() + "@" + parameter.hashCode()); 
      } else { 
       parameters.add(parameter == null ? "null" : parameter.toString()); 
      } 
     } 
    } 

    return result.getTestClass().getRealClass().getSimpleName() + "." + result.getMethod().getMethodName() + "(" 
      + StringUtils.join(parameters, ",") + ")"; 
} 

public static int getId(ITestResult result) { 
    final HashCodeBuilder builder = new HashCodeBuilder(); 
    builder.append(result.getTestClass().getRealClass()); 
    builder.append(result.getMethod().getMethodName()); 
    builder.append(result.getParameters()); 
    return builder.toHashCode(); 
} 

और यह भी अगर आप रुचि रखते हैं कि कैसे हमारे RetryAnalyzer काम करता है, नीचे देखें।

एक बात जो समझने के लिए महत्वपूर्ण है, यह है कि हम परीक्षण विधि के मानदंडों को दोनों में पुनः प्रयास करें और डुप्लिकेट परिणाम साफ़ करें। वे प्रासंगिक कारण हैं जिन्हें हम अक्सर डेटाप्रोवाइडर्स के साथ काम करते हैं।

import java.util.HashMap; 
import java.util.Map; 

import org.apache.logging.log4j.LogManager; 
import org.apache.logging.log4j.Logger; 
import org.testng.IRetryAnalyzer; 
import org.testng.ITestResult; 

public class RetryAnalyzer implements IRetryAnalyzer { 

    private static final Logger LOG = LogManager.getLogger(); 

    private static Integer maxRetries; 
    private final Map<Integer, Integer> retryCount = new HashMap<>(); 

    @Override 
    public boolean retry(ITestResult result) { 
     // only re-try failures 
     if (result.getStatus() == ITestResult.FAILURE) { 
      final String testName = TestListenerUtil.getName(result); 
      final int count = getRetryCount(result); 
      final int maxRetriesAllowed = getMaxRetriesAllowed(); 
      if (count < maxRetriesAllowed) { 
       retryCount.put(TestListenerUtil.getId(result), count + 1); 
       LOG.info("Retrying test (attempt " + (count + 1) + "/" + maxRetriesAllowed + "): " + testName); 
       return true; 
      } else { 
       LOG.error("Failing test after " + count + " retries: " + testName); 
      } 
     } 

     return false; 
    } 

    public boolean canRetry(ITestResult result) { 
     return result.getStatus() == ITestResult.FAILURE && getRetryCount(result) < getMaxRetriesAllowed(); 
    } 

    private int getRetryCount(ITestResult result) { 
     final int testId = TestListenerUtil.getId(result); 
     return retryCount.containsKey(testId) ? retryCount.get(testId) : 0; 
    } 

    public static int getMaxRetriesAllowed() { 
     return maxRetries == null ? Config.MAX_TEST_RETRIES : maxRetries; 
    } 
} 
+0

निर्माण में असफल रहेगा। मैं इस मुद्दे पर वापस आ गया हूं। बस एहसास हुआ कि testng ने व्यवहार को बदल दिया 6.9.5 में! जिन टेस्ट को पुनः प्रयास किया जा रहा है उन्हें अब छोड़ दिया जाएगा। Https://github.com/cbeust/testng/issues/878 देखें। इससे कोई टेस्टलिस्टर बन जाएगा जो असफल टेस्ट को अप्रचलित कर देगा। – MrSpock

+0

मैं जरूरी नहीं हूं: मुझे लगता है कि आप अभी भी छोड़े गए लोगों को हटाना चाहते हैं। लेकिन, यह जानकर बहुत अच्छा है कि यह 6.9.5 में बदल गया है! धन्यवाद। – mac

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