2011-10-18 9 views
5

인턴쉽을 위해 웹 응용 프로그램 테스트를 위해 TestNG 및 셀렌을 사용해야합니다. 하지만 문제가 발생합니다. 셀렌이나 브라우저가 임의의 이유로 작동하지 않아 작동하는 테스트가 "실패"로 표시됩니다. 이를 방지하기 위해 주석을 사용할 수 있습니다. 테스트가 한 번 성공하면 테스트는 "성공"으로 표시됩니다.하지만 문제는이 솔루션이 테스트 시간을 4 배로 늘리는 것이므로 매우 효율적이지 않습니다. .testng 및 seleniums 테스트를 최적화하는 방법

테스트 시간을 줄이려면 "테스트에 실패하면이 테스트를 다시 실행하고 테스트가 실패한 경우에만 규칙을 작성하고 두 번째, 세 번째 또는 네 번째로이 테스트를 "성공"으로 표시하십시오. 따라서 이러한 임의의 버그는 피할 수 있습니다. 그러나이 규칙을 작성하는 방법을 찾지 못했습니다. 청취자를 추가 할 수 있다는 것을 알았습니다. 따라서 "onTestFailure"이라는 메서드가있어서 테스트가 실패했을 때 뭔가 할 수 있습니다. 테스트를 실행하십시오.

실패한 테스트가 모두 저장되는 testng-failed.xml도 있습니다. 따라서이 테스트를 다시 실행하기 위해이 xml 파일을 실행할 수는 있지만 이전의 첫 번째 실행에서 보고서가 지워지지만 실패한 테스트는 두 번째 실행이 성공적이면 "성공"으로 표시됩니다. (젠킨스에 testNG/selenium을 통합 했으므로 모든 테스트가 포함 된 그래프가 있으므로이 방법은 적합하지 않지만이 방법은 테스트 시간을 4 배로 늘리지 않아 원하는 결과를 얻을 수 있습니다)

그렇게하는 방법에 대한 단서가 있다면 아주 좋을 것입니다.

+0

나는 testng-failed.xml을 3 번 실행하기 위해 테스트를 마쳤으며, 모든 테스트가 진행 중이고 많은 시간이 걸리지 않습니다. 그러나 Jenkins의 경우 testng-failed.xml이 마지막으로 실행될 때 testng-result.xml을 편집하므로 마지막 실행, testng이 시작되었으므로 그래프에 "1 테스트 실행, 1 성공"이 표시됩니다. 이 시험은 처음 3 번 실패했습니다. 이 방법은 모든 실패한 테스트가 포함 된 그래프를 생성하지만 모든 작업 테스트 (세 번째 실행되는 테스트 제외)는 표시되지 않습니다. 정확히 원하는 것은 아닙니다 ... 단서가 있습니까? – user1000499

답변

4

IRetryAnalyzer, 수신기 및 사용자 지정 리포터를 조합하여 원하는 것을 수행 할 수 있습니다.

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

큰 감사합니다. 아주 잘 작동합니다. D – user1000499

4

onTestFailure를 구현할 필요가 없습니다. TestNG는 테스트가 실패 할 때 자동으로 재 시도를 호출합니다. 따라서 onTestFailure를 재정의 할 필요가 없습니다. 이로 인해 메소드 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; 

    } 

위의 스레드에서 onTestFailure 구현으로 인해 두 번 호출되는 재 시도가 있습니다. 실패한 결과를 제거하여 재 시도 할 때 최신 결과를 사용합니다. 그렇지 않으면 종속성 테스트 방법이있는 경우 건너 뜁니다 (재 시도에서는 첫 번째 결과를 사용하므로 통과했습니다).보고하는 동안 실패한 재 시도 결과를 처리해야 할 수도 있습니다. 다시 시도한 후에 통과하는 테스트를 제거해야 할 수 있습니다.

 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"방법은 실제 테스트 코드를 개인 메소드로 옮기십시오. 주석이 달린 테스트 메소드에서 try 루프로 for 루프를 만든다.Throwable (모든 에러와 예외의 수퍼 클래스)를 찾을 곳을 잡아라. 오류가 발생하면 루프를 계속 진행하거나 성공 중단 루프에서 마지막 오류를 throw하십시오.

샘플 코드 :

@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 
} 

보통하지만, 그것은 무작위로 실패하지 않는 테스트를 작성하는 것이 좋습니다. 또한이 방법을 사용하면 몇 번의 시도가 실패했는지에 대한 정보가 없으므로 결국 중요한 정보가됩니다. 개인적으로 실패 할 때 Jenkins의 전체 테스트 클래스/스위트를 다시 실행하고 실패한 이유를 조사합니다.

관련 문제