Как оптимизировать тестирование и тестирование селена - PullRequest
5 голосов
/ 18 октября 2011

Для моей стажировки я должен использовать TestNG и селен для тестирования веб-приложения.Но у меня есть проблема, иногда селен или браузер не работает по какой-то случайной причине, поэтому рабочий тест помечается как «проваленный».Чтобы избежать этого, я могу использовать аннотацию @Test(invocationCount = 4, successPercentage = 25), тогда, если тест пройден один раз, тест помечается как «Успешно», это хорошо, но проблема в том, что это решение умножает время тестирования на 4, это неочень эффективный.

Что я могу сделать, чтобы сократить время на тестирование, так это написать какое-то правило «если тест не пройден, перезапустите этот тест (и только если тест не пройден), и если он сработал второй, третий,или в четвертый раз, затем пометьте этот тест как «успешный», так что я могу избежать этих случайных ошибок.Но я не нашел, как написать это правило, я увидел, что мы можем добавить слушателя, поэтому у нас есть метод с именем "onTestFailure", поэтому я могу что-то сделать, когда тест не пройден, но я не знаю, как это сделать.повторите тест.

Я также нашел testng-failed.xml, в котором сохранены все неудачные тесты, поэтому мы можем запустить этот xml-файл для повторного запуска этих тестов, но это сотрет отчет с предыдущего первого запуска, но я хочу просточто неудачные тесты помечаются как «успешные», если второй запуск прошел успешно.(Я интегрировал testNG / selenium в Jenkins, поэтому у меня есть график со всеми тестами, поэтому этот метод не очень адаптирован, но этот метод не увеличивает время тестирования на 4, и это то, что я хочу)

Так что, если у вас есть какие-либо подсказки, как это сделать, было бы очень приятно.

Ответы [ 3 ]

4 голосов
/ 01 октября 2012

Вам не нужно реализовывать 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);
        }

Надеюсь, это поможет лучше понять попытку.

4 голосов
/ 21 октября 2011

Вы можете использовать комбинацию 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, похоже, есть ошибка, которая фактически приводит к тому, что некоторые результаты теста сообщаются как пропущенные, так и неудачные. Чтобы предотвратить это, я рекомендую переопределить любой Reporter, который вы хотите использовать, и включить метод, такой как приведенный ниже:

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, и указать retryAnalyzer в аннотации @Test.

0 голосов
/ 06 ноября 2014

Остальные ответы - «правильный» путь. Для «быстрого и грязного» способа просто перенесите реальный тестовый код в приватный метод. В вашем аннотированном тестовом методе создайте цикл for с try..catch внутри, где вы ищите Throwable (суперкласс всех ошибок и исключений). При ошибке просто продолжите цикл или сгенерируйте последнюю ошибку, при успешном завершении цикла.

Пример кода:

@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 в случае сбоя и выяснил, почему он не удался.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...