понедельник, 16 декабря 2013 г.

Тестирование верстки 2

Тестирование с помощью fighting layout bugs

Я думаю не многие знают про гугловую open-source либу,для тестирования верстки и различных layouts,а она совсепм даже не плоха.
Взять ее можно вот тут.
Если кратко,что она умеет?
Находит битые ссылки:
  • Сканирует  HTML теги <img> и проверяет src атрибуты.
  • Сканирует CSS  вск атрибуты style и <style> елементы в HTML и все указанные URL в них.
  • Проверяет фавиконки по урлам.
Проверяет необходимый горизонтальный скроллинг

 Можно указать минимально поддерживаемое разрешение экрана для вашей веб страницы
примерно так:


 
FightingLayoutBugs flb = new FightingLayoutBugs(); flb.configure(DetectNeedsHorizontalScrolling.class).setMinimalSupportedScreenResolution(800, 600);

По умолчанию минимальное разрешение 1024 x 768.

  • Так же проверяет текст на слишком маленький контраст.
  • Распознает текст, который очень близко или перекрывает горизонтальный край
  • Распознает текст, который очень близко или перекрывает вертикальный край
И собственно прикрутить,ее очень просто

 
    FirefoxDriver driver = new FirefoxDriver();
    try {
        String testPageUrl = "http://www.test.de/";
        driver.get(testPageUrl);
        WebPage webPage = new WebPage(driver);
        FightingLayoutBugs flb = new FightingLayoutBugs();
        final Collection layoutBugs = flb.findLayoutBugsIn(webPage);
        System.out.println("Found " + layoutBugs.size() + " layout bug(s).");
        for (LayoutBug bug : layoutBugs) {
            System.out.println(bug);
        }
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        driver.quit();
    }


 В общем я думаю стоит попробовать.

четверг, 5 декабря 2013 г.

Тестирование верстки

Тестирование верстки

В общем то идея далеко не новая,как быстро и автоматизированно следить за тем,чтобы при новом билде не расползлась верстка в разных браузерах.
Браузеров много,проект большой,мануальные тестировщики все не успеют.
Попробуем автоматизировать.
Для этого подойдет Selenium WD(т.к. у него поддержка кучи браузеров и снятие скриншотов,то которое нам нужно) и всего навсего средства Java чтобы следить за соответствием скринов.
Не буду говорить, как именно нужно снимать и проверять скриншоты,но мне кажется удобно или сделать пачку "эталонных скринов" и новые сравнивать с ними,или лезть на боевой сервер,делать скрин оттуда,а после снимать скрин на qa-стенде.
Второй вариант дольше,но надежнее в плане не устаревани "эталонных скриншотов".
В общем хватит об этом,как это сделать?
Примерно так:
Через WD  снять скрин можно так:

 
   public void makeScreenshot(String methodName) {
        try {
            File scrFile = ((TakesScreenshot)driver).getScreenshotAs(OutputType.FILE);
            FileUtils.copyFile(scrFile, new File("target" + File.separator + "failure_screenshots" +
                    File.separator + methodName+".png"));
        } catch (IOException e1) {
            e1.printStackTrace();
        }
    } 
Конечно это не единственный способ для снятия скриншотов,но сойдет.
Вроде есть много java-библиотек для работы с изображениями,но стоящую и для такой не трудной задачи искать действительно тяжело.(я вроде как не нашел)
в общем можно использовать этот класс:


import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * I am gonna pass two images and I am gonna recort only the differences
 * trying to catch if there is a different object or not int the scene
 *
 * @author maikon
 */
public class CheckingDifferentImages {

    public static void checkDifference(String pathToTheFirstScreen, String pathToTheSecond, String nameDifference) {
        BufferedImage im1 = null;
        BufferedImage im2 = null;
        try {
            //loading the two pictures
            //read and load the image
            BufferedImage input = ImageIO.read(new File("target"+File.separator+"failure_screenshots"+File.separator+pathToTheFirstScreen));
            //build an image with the same dimension of the file read
            im1 =
                    new BufferedImage(input.getWidth(), input.getHeight(), BufferedImage.TYPE_INT_ARGB);
            //object create to draw into the bufferedImage
            Graphics2D g2d = im1.createGraphics();
            //draw input into im
            g2d.drawImage(input, 0, 0, null);
            //making all again for the second image

            BufferedImage input2 = ImageIO.read(new File("target"+File.separator+"failure_screenshots"+File.separator+pathToTheSecond));
            //build an image with the same dimension of the file read
            im2 =
                    new BufferedImage(input2.getWidth(), input2.getHeight(), BufferedImage.TYPE_INT_ARGB);
            //object create to draw into the bufferedImage
            Graphics2D g2d2 = im2.createGraphics();
            //draw input into im
            g2d2.drawImage(input2, 0, 0, null);
        } catch (IOException ex) {
            Logger.getLogger(CheckingDifferentImages.class.getName()).log(Level.SEVERE, null, ex);
        }

        showDifference(im1, im2, nameDifference);

    }

    public static void showDifference(BufferedImage im1, BufferedImage im2, String nameDifference) {
        BufferedImage resultImage =
                new BufferedImage(im1.getWidth(), im2.getHeight(), BufferedImage.TYPE_INT_ARGB);

        double THR = 50;
        int area = 0;
        for (int h = 0; h < im1.getHeight(); h++) {
            for (int w = 0; w < im1.getWidth(); w++) {

                int red1 = 0xff & (im1.getRGB(w, h) >> 16);
                int green1 = 0xff & (im1.getRGB(w, h) >> 8);
                int blue1 = 0xff & im1.getRGB(w, h);


                int red2 = 0xff & (im2.getRGB(w, h) >> 16);
                int green2 = 0xff & (im2.getRGB(w, h) >> 8);
                int blue2 = 0xff & im2.getRGB(w, h);

                //euclidian distance to estimate the simil.
                double dist = 0;
                dist = Math.sqrt(Math.pow((double) (red1 - red2), 2.0)
                        + Math.pow((double) (green1 - green2), 2.0)
                        + Math.pow((double) (blue1 - blue2), 2.0));
                if (dist > THR) {
                    resultImage.setRGB(w, h, im2.getRGB(w, h));
                    area++;
                } else {
                    resultImage.setRGB(w, h, 0);
                }
           //2nd option
           /*     if (dist > THR) {
                    resultImage.setRGB(w, h,255);
                    area++;
                } else {
                    resultImage.setRGB(w, h, im1.getRGB(w, h));
                }*/
            } //w
        } //h
        try {
            File fileScreenshot = new File("target" + File.separator + "DifferenceScreens" + File.separator + nameDifference);
            fileScreenshot.getParentFile().mkdirs();
            ImageIO.write(resultImage, "PNG", fileScreenshot);
        } catch (IOException ex) {
            Logger.getLogger(CheckingDifferentImages.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
    //end functionn

}

Попробуем что нить простое(не придираться,это для примера)

 
  @Test
    public void testYandex(){
        get("http://www.yandex.ru/");
        makeScreenshot("1");
        get("http://www.yandex.ru/");
        makeScreenshot("2");
        CheckingDifferentImages.checkDifference("1.png","2.png","diff.png");
    }

В результате:
1й скрин
2й скрин
и отличие(если вы заметили то в классе 2 варианта,один закомменитрован) так что:
и 2м способом

Вот и все.

среда, 4 декабря 2013 г.

Security Regression Tests

 Тестированиe безопасности в регрессе

В общем у многих есть регресс сьюты,но мало у кого есть какое-либо тестирование безопасности,я попробую рассказать ,как его можно добавить без особых затрат.
И так,подразумеваем,что у нас есть рабочий регресс который покрывает большую(а лучше полную) часть нашего функционала веб-приложения.
Значит нужно к нему привязать хороший сканер уязвимостей,который поможет находить проблемы на более ранних стадиях разработки.
Советую обратить внимание на инструмент OWASP ZAP, потому что он (как мне кажется) полностью удовлетворяет нашим требованиям.(ну и + OWASP классная команда с активным комьюнити и все такое)
В общем  для начала о нем,что он из себя представляет.Можно погуглить и посмотреть на эти слайды:



А теперь как это работает у меня

Есть сборщик Maven который собирает и запускает наши тесты, и поднимает тулзу Owasp ZAP,которая поднимает свой прокси который я ему задал.
Затем,мы поднимаем браузер с настроенным прокси(указываем прокси ZAP),в котором будут выполняться тесты.
Это позволит нам видеть все запросы и ответы производимые тестами и так же позволит нам отслеживать и проверять все AJAX запросы (которые не всегда могут быть протестированы).
ZAP пассивно просматривает все ответы от веб-приложения и проводит проверку по заданным "рулам".
Пассивное сканирование не изменяет ответы и запросы и следовательно безопасно в использовании на любых площадках.
Сканирование выполняется в фоновом потоке, что исключает снижение скорости работы приложения.

После прогона всего сьюта можно пробежаться пауком по заданному узлу,чтобы найти то,что не прошло через наше прокси.
После чего запускаем активное скнирование
Активное сканирование пытается найти потенциальные уязвимости с использованием известных OWASP аттак.(а их совсем не мало)
Не желательно использовать такой вид тестирования на боевом сервере.
Естественно, активное сканирование находит только определенные виды уязвимостией,логические уязвимости,как контроль доступа, проверены быть не могут и должны проверятся мануальным тестированием.
И да,проводится также проверка на CSRF форм (это проверка на сабмит форм со случайным параметром, используемых для защиты от CSRF атак.)

Вот и все,всем спасибо.

суббота, 16 ноября 2013 г.

Дожидаемся полной загрузки страницы в Selenium WebDriver

Дожидаемся полной загрузки страницы в Selenium WebDriver

Собственно говоря, иногда нужно дождаться полной загрузки страницы прежде чем выполнять какие либо действия.
Или когда не подгружается какой либо ресурс ваши тесты могут висеть бесконечно(что гораздо хуже)
Вообще в интернете советуют использовать либо implicit wait WD,либо завязывать на какой либо элемент с которым мы хотим работать после загрузки.
Можно делать так как советуют,но иногда этого не достаточно.Как в примере с недоступным ресурсом который можно очень долго ждать.
Я предпочитаю примерно такую реализацию:

 
  public void waitForPageLoaded() {
        ExpectedCondition expectation = new
                ExpectedCondition() {
                    public Boolean apply(WebDriver driver) {
                        return WebDriverController.executeScript("return document.readyState").toString().equals("complete");
                    }
                };

        try {
            getInstanceWaitDriver().until(expectation);
        } catch(Throwable error) {
            Assert.fail("Timeout waiting for Page Load Request to complete.");
        }
    }
Можно назвать это хаком,т.к я использую JavaScript, но я так не считаю)
Всем спасибо.

суббота, 10 августа 2013 г.

TestNG Custom Listener

Custom TestNG Listener

Иногда стоит задача,формировать test suite, не в xml а programmatically, например это может быть нужно,когда мы хотим формировать тесты в зависимости от конфигов. Это сделает их гибче и проще настраиваемыми.
Чтобы просто создать и запустить testNG suite нам потребуется всего пара строчек(которые кстати хорошо описаны в документации testNG)

 
        TestNG tng = new TestNG();
            TestListenerAdapter tla = new TestListenerAdapter();
            List suites = new ArrayList();
            tng.addListener(tla);
            XmlSuite suite = new XmlSuite();
            XmlTest testXml = new XmlTest(suite);
            List excludeGroup = new ArrayList ();
            excludeGroup.add(test.getExcludedGroups());
            testXml.setXmlClasses(test.getClassToRun());
            testXml.setExcludedGroups(excludeGroup);
            suites.add(suite);
            tng.setXmlSuites(suites);
            tng.run(); 
            testsNg.run();
Проблема такого подхода,только в том,что сейчас ошибки которые могу быть в тестах совершенно не наглядны,и во время выполнения большого сьюта их никак не увидеть.
Значит нужно добавить свои средства:

 
   TestNG tng = new TestNG();
            TestListenerAdapter tla = new TestListenerAdapter();
            List suites = new ArrayList();
            tng.addListener(tla);
            XmlSuite suite = new XmlSuite();
            XmlTest testXml = new XmlTest(suite);
            List excludeGroup = new ArrayList ();
            excludeGroup.add(test.getExcludedGroups());
            testXml.setXmlClasses(test.getClassToRun());
            testXml.setExcludedGroups(excludeGroup);
            suites.add(suite);
            tng.setXmlSuites(suites);
            tng.run(); 
    List failedTests = Lists.newArrayList();
            failedTests.addAll(tla.getFailedTests());
            failedTests.addAll(tla.getConfigurationFailures());
            if (!failedTests.isEmpty()) {
                String header = String.format("Combined Messages (Total:%d)", failedTests.size());

                List errorMessages = Lists.newArrayList();
                errorMessages.add(header);
                errorMessages.addAll(Lists.transform(failedTests, new Function() {
                    int i = 1;
                    @Override
                    public String apply(ITestResult testResult) {
                        String stackTraceString = Throwables.getStackTraceAsString(testResult.getThrowable());
                        String template = "Message-%d: %n %s";
                        return String.format(template, i++, stackTraceString);
                    }
                }));

                String message = Joiner.on(LINE_SEPARATOR).join(errorMessages);
                throw new AssertionError(message);
            }


С добавлением такого кода,после сьюта выведется вся информация об ошибках со stacktraceом.
Если же нам нужна информация еще во время его прохождения,чтобы не тратить наше драгоценное время на ожидание,то нужно добавить

 
  @AfterMethod
    public void tearDown2(ITestResult result) {

        if (!result.isSuccess()) {
            makeScreenshot(result.getName());
            log.error("Test FAILED! Method:" + result.getName() + ". StackTrace is "+ Throwables.getStackTraceAsString(result.getThrowable()));
        }
    }

Думаю это поможет,всем спасибо.

суббота, 6 июля 2013 г.

SSL Trust Manager

Хак для самоподписных сертификатов.

Код отлично работающий с Http, может совершенно отказываться работать с https,если сертификаты самоподписные.(что чаще всего и есть на тестовых площадках)Для примера, если вы используете в Java класс HttpURLConnection то он выдаст следующее исключение:

 
javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: 

Чтобы его избежать, нам нужно отключить проверку сертификатов в https.
Это исключение нам дает класс URL через который обращается HttpURLConnection.Для тестирования достаточно перегрузить trust manager, чтобы он доверял всем сертификатам)

 

// Create a trust manager that does not validate certificate chains 
    TrustManager[] trustAllCerts = new TrustManager[]{ 
        new X509TrustManager() { 
            public java.security.cert.X509Certificate[] getAcceptedIssuers() { 
                return null; 
            } 
            public void checkClientTrusted( 
                java.security.cert.X509Certificate[] certs, String authType) { 
            } 
            public void checkServerTrusted( 
                java.security.cert.X509Certificate[] certs, String authType) { 
            } 
        } 
    }; 
     
    // Install the all-trusting trust manager 
    try { 
        SSLContext sc = SSLContext.getInstance("SSL"); 
        sc.init(null, trustAllCerts, new java.security.SecureRandom()); 
        HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory()); 
    } catch (Exception e) { 
    } 
     
    // Now you can access an https URL without having the certificate in the truststore 
    try { 
        URL url = new URL("https://hostname/index.html"); 
    } catch (MalformedURLException e) { 
    } 


Больше такой проблемы не появится.

суббота, 25 мая 2013 г.

Hack Xpath

Хак для Selenium WebDriver

Собственно,очень удобно использовать аннотации в WD
@FindBy(id = "idOfYourElement")
WebElement myLocator;
Но иногда требуется достать локатор из используемого элемента.Никакого метода для этого нет,поэтому будем хакать.
Путь это немного костыльно,но иногда необходимо.


  public static String getXPath(WebElement element) {
        String jscript = "function getPathTo(node) {" +
                "  var stack = [];" +
                "  while(node.parentNode !== null) {" +
                "    stack.unshift(node.tagName);" +
                "    node = node.parentNode;" +
                "  }" +
                "  return stack.join('/');" +
                "}" +
                "return getPathTo(arguments[0]);";
        return "//"+(((JavascriptExecutor)driver).executeScript(jscript, element));
    }
Так можно получить локатор по xpath.
Но на мой взгляд,к этому нужно прибегать в крайних случаях.
Всем спасибо.