2011-10-18 14 views
5

Đối với thực tập của tôi, tôi phải sử dụng TestNG và selen để thử nghiệm một ứng dụng web. Nhưng tôi có một vấn đề, đôi khi selen hoặc trình duyệt không hoạt động vì một số lý do ngẫu nhiên, do đó, một thử nghiệm làm việc được đánh dấu là "không thành công". Để tránh điều đó, tôi có thể sử dụng chú thích @Test(invocationCount = 4, successPercentage = 25), sau đó nếu thử nghiệm thành công một lần, thử nghiệm được đánh dấu là "Thành công", điều đó tốt nhưng vấn đề là giải pháp này nhân thời gian thử nghiệm 4, điều này không hiệu quả lắm .Làm thế nào để tối ưu hóa các kiểm tra testng và seleniums

Điều tôi có thể làm để giảm thời gian thử nghiệm là viết một số quy tắc "nếu thử nghiệm không thành công, chạy lại thử nghiệm này (và chỉ khi thử nghiệm thất bại), và nếu nó hoạt động thứ hai, thứ ba hoặc lần thứ tư, sau đó đánh dấu thử nghiệm này là "thành công" "Vì vậy, tôi có thể tránh các lỗi ngẫu nhiên này. Nhưng tôi không tìm thấy cách viết quy tắc này, tôi thấy rằng chúng ta có thể thêm người nghe, vì vậy chúng tôi có một phương pháp gọi là "onTestFailure" để tôi có thể làm điều gì đó khi thử nghiệm không thành công nhưng tôi không biết cách chạy thử nghiệm.

Tôi cũng tìm thấy testng-failed.xml nơi tất cả các kiểm tra không thành công được lưu, vì vậy chúng tôi có thể chạy tệp xml này để chạy lại các thử nghiệm này, nhưng điều này sẽ xóa báo cáo khỏi lần chạy đầu tiên trước đó, nhưng tôi chỉ muốn kiểm tra không thành công được đánh dấu là "thành công" nếu lần chạy thứ hai thành công. (Tôi đã tích hợp testNG/selenium vào Jenkins, vì vậy tôi có đồ thị với tất cả các xét nghiệm, vì vậy phương pháp này không thích nghi lắm, nhưng phương pháp này không nhân thời gian thử nghiệm 4 và đây là điều tôi muốn)

Vì vậy, nếu bạn có bất kỳ đầu mối nào về cách thực hiện điều đó, nó sẽ rất tuyệt vời.

+0

Tôi đã thử nghiệm để chạy testng-failed.xml 3 lần, và sau đó tất cả các thử nghiệm đang hoạt động và không mất nhiều thời gian. Nhưng với Jenkins, khi testng-failed.xml chạy lần cuối, điều này sẽ chỉnh sửa tệp testng-result.xml, vì vậy bây giờ biểu đồ cho biết "chạy thử 1, 1 thành công", bởi vì lần chạy cuối cùng, testng đã khởi chạy chỉ thử nghiệm này thất bại trong 3 lần đầu tiên. Phương pháp này sẽ tạo ra một đồ thị với tất cả các bài kiểm tra không thành công, nhưng tất cả các bài kiểm tra làm việc (ngoại trừ các bài kiểm tra được chạy lần thứ ba) sẽ không được chỉ định, nó không chính xác những gì tôi muốn ... bất kỳ đầu mối? – user1000499

Trả lời

4

Bạn có thể sử dụng kết hợp IRetryAnalyzer, Trình nghe và trình báo cáo tùy chỉnh để thực hiện những gì bạn đang tìm kiếm.

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

Tuy nhiên, dường như có một lỗi trong vòng TestNG mà thực sự gây ra một số kết quả kiểm tra được báo cáo là cả hai bỏ qua và thất bại. Để ngăn chặn điều này, tôi khuyên bạn nên ghi đè lên bất cứ điều gì Reporter bạn muốn sử dụng và bao gồm một phương pháp như một trong những bao gồm dưới đây:

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

Sau khi tất cả điều này được thực hiện, bạn có thể thêm các phóng viên sử dụng bằng .addListener và chỉ định retryAnalyzer trong chú thích @Test.

+0

Cảm ơn bạn rất lớn, nó hoạt động rất tốt, hoàn hảo: D – user1000499

4

Bạn không cần triển khai onTestFailure. TestNG tự động thử lại khi kiểm tra không thành công. Vì vậy, không cần phải ghi đè lênTestFailure. điều này gây ra phương pháp thử lại 2 cuộc gọi. Tôi đã triển khai thử lại như sau.


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; 

    } 

Trong chuỗi ở trên, thử lại được gọi hai lần vì triển khai onTestFailure. Tôi xóa các kết quả không thành công để khi bạn thử lại, nó sử dụng kết quả mới nhất. Nếu không, nếu bạn có phương pháp kiểm tra phụ thuộc, nó sẽ bị bỏ qua (mặc dù thử lại nó được truyền vì nó sử dụng kết quả đầu tiên) .Bạn có thể phải xử lý các kết quả thử lại không thành công trong khi báo cáo. Bạn có thể phải xóa các bài kiểm tra đang chuyển sau khi thử lại như sau.

 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); 
     } 

Hy vọng sẽ giúp bạn hiểu thử lại tốt hơn.

0

Các câu trả lời khác là cách "đúng". Đối với một cách "nhanh chóng" chỉ cần di chuyển mã thử nghiệm thực tế đến một phương pháp riêng. Trong phương pháp thử nghiệm được chú thích của bạn, hãy thực hiện vòng lặp for with try ..bắt bên trong nơi bạn tìm Throwable (superclass của tất cả các lỗi và ngoại lệ). Khi lỗi chỉ tiếp tục vòng lặp hoặc ném lỗi cuối cùng, vào vòng lặp thành công.

Mẫu mã:

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

Thông thường, tuy nhiên, nó tốt hơn để viết bài kiểm tra mà không thất bại một cách ngẫu nhiên. Cũng sử dụng cách tiếp cận này, bạn không có thông tin về số lần thử thất bại, đây là một thông tin quan trọng. Cá nhân tôi thay vì chạy lại toàn bộ lớp/bộ bài kiểm tra trên Jenkins về lỗi, và điều tra tại sao nó thất bại.