четверг, 31 января 2013 г.

Testing in example

О видах тестирования на примере

среда, 30 января 2013 г.

About test plans

О тест планах.

Сам я совсем не сторонник больших тест планов,и увидев такую статью у Pradeep Soundararajan,не мог ей не поделиться.

  • 98% тест планов никогда не обновляются и не поддерживаются в актуальном состоянии, короче говоря, о них просто забывают
  • Первые 5 страниц тест плана содержат историю изменений, которая не интересует даже тех, чьи имена в ней перечислены
  • Раздел описывающий цели тестирования  является самой забавной частью этого документа. Порой, когда тестировщик сообщает о серьезной проблеме, кто-нибудь цитирует этот раздел, намекая на то, что находить проблемы такого рода не входило в его задачи и… Опа! Продукт и проблема живут дальше бок о бок
  • Конечные пользователи могли бы экономить миллионы долларов, если бы компании, разрабатывающие ПО, перестали писать тест планы
  • Не имеет значения насколько хорошо или плохо написан ваш тест план – тестировщики все равно будут писать тест кейсы так, как они считают нужным
  • На проекте, который длится 4 года, никто и никогда не вспоминает о тест плане
  • Тест план – отличный инструмент для аутсорсинговой компании, который позволяет потребовать денег у заказчика, не проводя при этом тестирование как таковое
  • Каждый, кто принял участие в процессе написания тест плана, испытывает  чувство глубочайшего удовлетворения в тот момент, когда этот документ завершен. При этом не важно, есть ли у них план тестирования или нет
  • Стоимость рецензирования документа, который никто не собирается использовать, слишком высока
  • Тот, кто считает, что он не готов к началу тестирования, поскольку у него нет тест плана, на самом деле не является тестировщиком
  • Небольшой понятный тест план, который вы сможете поддерживать в актуальном состоянии, куда лучше, чем очень большой и подробный до которого никому нет дела
  • Одна хорошая ассоциативная карта  заменит вам тысячу прекрасных тест планов
  • Тест план – это всегда документ, но далеко не всегда это план тестирования
  • Заставляя тестировщика писать документ, который никто не будет читать, не надейтесь, что он вложит в его написание душу
  • Некоторые тест планы устаревают еще до того момента, как в их черновике будет дописана последняя строчка
  • Некоторые рецензенты добиваются того, чтобы тест план был идеален, при этом совсем не факт, что они знают хоть что-нибудь о разрабатываемом продукте
  • Тот, кто знает, что такое альтернативная стоимость, скорее всего, напишет тест план куда лучше того, кто о ней не знает

Thusidides Selenium

Thusidides Selenium

Расскажу про небольшой Framework на Selenium.
Наверное все таки большинство из нас пользуется Selenium WD и знает что наверное самое слабое место у него-это отчеты(вообще говоря их вообще нет),для репортинга в основном используются или плагины или отчеты с Junit или TestNG(если это Java).
Так вот Thsidides призван внести в разработку тестов не только некоторые улучшения,но самое главное хорошие отчеты.

Немного истории!(надо ж как то разнообразить рассказ)
Thusidides переводится как Фукиди́д,был древнегреческим историком,который прославился именно качественными репортами,отсюда и название этого фреймворка.
История закончилась,перейдем к делу.

Тесты набрасывались для примера и чтобы просто показать принцип,естественно они не поддерживаемые и все такое.

Для начала,чтобы подключить его к нашему проекту,добавим в Maven следующее:


  4.0.0

  webtests
  tests
  1.0-SNAPSHOT
  jar

  wikipediawebtests
  http://maven.apache.org

    
        UTF-8
        0.9.88
    

    
        
            junit
            junit
            4.8.2
        
        
            org.hamcrest
            hamcrest-all
            1.1
        
        
            net.thucydides
            thucydides-junit
            ${thucydides.version}
        
        
            org.slf4j
            slf4j-simple
            1.6.1
            pom
        
    
    
        
            
                org.apache.maven.plugins
                maven-compiler-plugin
                2.3.2
                
                    1.5
                    1.5
                
            
            
                net.thucydides.maven.plugins
                maven-thucydides-plugin
                ${thucydides.version}
            
        
    
                      

Все после добавления в проект,начнем разбираться как он нам предлагает структурировать наши тесты.
Вообще он больше рассчитан на приемочные тесты.Вы это сами заметите.
Создается общий класс для требований,фич и.т.д.


public class Application {
    @Feature
        public class TestPageBook {}
        public class TestAuth{}
        public class TestSearch{}
}
Как мы видим,в одной фиче может быть несколько классов и конечно может быть несколько фич.
После этого создается класс с  тестом

@RunWith(ThucydidesRunner.class)
@Story(Application.TestPageBook.class)
public class TestPageBook {

    @Managed
    public WebDriver driver;

    @ManagedPages(defaultUrl = "http://m.megafonpro.ru/")
    public Pages pages;

    @Steps
    public StepsinBook book;

    @Test
    public void testBook() throws Exception {
        book.getMain("http://m.megafonpro.ru/");   //Вход на главную страницу тестируемого ресурса
        book.AllBooks();                                                //Переход во вкладку Все книги      
        book.search();                                                 //Поиск книги с поисковым выражением "Книга
        book.catalog();                                                 //Проверка каталога книг по жанрам

    }
    @Pending @Test              //данная аннотация значит,что тест еще не имплементирован
    public void testBuyBook(){}

}

Далее описываются шаги самого теста,Steps как они называются здесь.

public class StepsinBook extends ScenarioSteps {
    public StepsinBook(Pages pages) {
        super(pages);
    }
    public BookPage getPageBook()
    {
        return  getPages().currentPageAt(BookPage.class);
    }

    @Step
    public void getMain(String url)
    {
        getPageBook().getMainPage(url);
    }

    @Step
    public void AllBooks()
    {
        getPageBook().allBooks();
    }

    @Step
    public void search(){
        getPageBook().search("Книга");
    }

    @Step
    public void catalog(){
        getPageBook().catalog();
    }
}

И привычная нам работа с WD с PageObject.

package Actions;
public class BookPage extends PageObject {
    private ShareFunc func;
    @FindBy(linkText = "Все книги")
    WebElement allbooksButton;

    @FindBy(linkText = "Поиск")
    WebElement searchButton;

    @FindBy(name = "query")
    WebElement searchField;

    @FindBy(css = "button")
    WebElement searchBegin;
    @FindBy(linkText = "Большая книга кремлевских тайн.")
    WebElement searchBook;

    @FindBy(linkText = "Каталог")
    WebElement catalog;

    @FindBy(linkText = "Малая форма")
    WebElement littleForm;

    @FindBy(linkText = "Повести")
    WebElement story;

    @FindBy(linkText = "Всего лишь капелька яда")
    WebElement oneOfStories;

    public BookPage(WebDriver driver) {
        super(driver);
        func=new ShareFunc(driver);

    }

    public void getMainPage(String url) {
        getDriver().get(url);

    }

    public void allBooks() {

        func.safeClick(allbooksButton);

    }

    public void search(String searchWord) {
        func.safeClick(searchButton);
        func.sendKeys(searchField, searchWord);
        func.safeClick(searchBegin);
        func.safeClick(searchBook);

    }

    public void catalog() {
        func.safeClick(catalog,getDriver());
        assertEquals("КАТАЛОГ",findElement(By.cssSelector("div.title > strong")).getText());
        func.safeClick(littleForm);
        assertEquals("МАЛАЯ ФОРМА",findElement(By.cssSelector("div.title > strong")).getText());
        func.safeClick(story, getDriver());
        assertEquals("МАЛАЯ ФОРМА - ПОВЕСТИ",findElement(By.cssSelector("div.title > strong")).getText());
        func.safeClick(oneOfStories);
        assertTrue(getPageSource().contains("Марина Серова"));
    }
}

Иерархия тестов примерно такая,сначала мне не понравилась,но если с ней поработать,то весьма удобно.
Далее в запускаем через maven
mvn test thucydides:aggregate
 
И он нам забацает вот такой отчет.




Немного о более тонкой настройке:
Для выбора запуска браузера запускаем Maven с опцией:
-Dwebdriver.driver=chrome
А для параллельного запсука тестов например используем сигнатуры перед классом с тестами
@RunWith(ThucydidesParameterizedRunner.class)
@Concurrent(threads="3")
 

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

Testing SMS and USSD with AT commands

Тестирование через SMS и USSD(с использованием AT комманд)

Бывают такие задачи,когда использование только программной части реализации нам недостаточно,скажем когда при регистрации код подтверждения отправляется нам в смс,автоматизировать такой сценарий-сложно,но можно)
Собственно для автоматизации таких сценариев с использованием мобильных устройств нам понадобится 3g модем,а все остальное я расскажу здесь.
Возможно получится большая статья,но это для того чтобы команда "Р" все сделала правильно!)
Начнем.
Для начала,нам потребуется Java библиотека отсюда-http://smslib.org/
Она будет осуществлять основное взаимодействие между мобильным устройством и нашим тестом.

Поподробнее об установке:
Для корректной работы,этой библиотеки нам понадобятся следующие зависимости:
1.RxTx который можно взять здесь.
После этого 
  • Файл RXTXcomm.jar нужно положить JDKDIR/jre/lib/ext/
  • А нужную библиотеку (для Linux 32bit librxtxSerial.so) в JDKDIR/jre/bin/
2.Smslib использует log4j в качестве логгера,ставим его.
Скачиваем log4j  отсюда. А файл log4j-1.2.15.jar помещаем в ваш classpath или в Java's lib/ext.

3.Apache Jakarta Commons - NET

Скачиваем Apache Jakarta Commons/NET отсюда. А файл commons-net-2.0.jar помещаем в ваш classpath или в Java's lib/ext.


4.JSMPP Library
То же самое с JSMPP ,скачиваем  отсюда и jsmpp-2.1.0.jar помещаем в ваш classpath или в Java's lib/ext.

Тем,кто больше любит Maven-вот пожалуйста
 

 org.rxtx
 rxtx
 2.1.7

            
        
            org.smslib
            smslib
            3.5.2
        
        
            log4j
            log4j
            1.2.17
            
    
    
        
            nightlabs
            nightlabs repo
            http://smslib.googlecode.com/svn/maven2/
        
    

Подключаем модем в USB порт.
Вводим lsub
для вывода подключенных устройств,ищем там свой модем.

Теперь даем права на чтение и запись с портов:
sudo       chmod o+rw /dev/ttyU*

В Java коде пробуем исполнить следующий код(Обращаю внимание,что код не мой,ибо он дико вырвиглазный,а код из доков самой библиотеки):
import org.smslib.helper.CommPortIdentifier;
import org.smslib.helper.SerialPort;

import java.io.InputStream;
import java.io.OutputStream;
import java.util.Enumeration;
import java.util.Formatter;

public class CommTest
{
    private static final String _NO_DEVICE_FOUND = "  no device found";

    private final static Formatter _formatter = new Formatter(System.out);

    static CommPortIdentifier portId;

    static Enumeration portList;

    static int bauds[] = { 9600, 14400, 19200, 28800, 33600, 38400, 56000, 57600, 115200 };


    private static Enumeration getCleanPortIdentifiers()
    {
        return CommPortIdentifier.getPortIdentifiers();
    }

    public static void main(String[] args)
    {
        System.out.println("\nSearching for devices...");
        portList = getCleanPortIdentifiers();


        while (portList.hasMoreElements())
        {
            portId = portList.nextElement();
            if (portId.getPortType() == CommPortIdentifier.PORT_SERIAL)
            {
                _formatter.format("%nFound port: %-5s%n", portId.getName());
                for (int i = 0; i < bauds.length; i++)
                {
                    SerialPort serialPort = null;
                    _formatter.format("       Trying at %6d...", bauds[i]);
                    try
                    {
                        InputStream inStream;
                        OutputStream outStream;
                        int c;
                        String response;
                        serialPort = portId.open("SMSLibCommTester", 1971);
                        serialPort.setFlowControlMode(SerialPort.FLOWCONTROL_RTSCTS_IN);
                        serialPort.setSerialPortParams(bauds[i], SerialPort.DATABITS_8, SerialPort.STOPBITS_1, SerialPort.PARITY_NONE);
                        inStream = serialPort.getInputStream();
                        outStream = serialPort.getOutputStream();
                        serialPort.enableReceiveTimeout(1000);
                        c = inStream.read();
                        while (c != -1)
                            c = inStream.read();
                        outStream.write('A');
                        outStream.write('T');
                        outStream.write('\r');
                        Thread.sleep(1000);
                        response = "";
                        StringBuilder sb = new StringBuilder();
                        c = inStream.read();
                        while (c != -1)
                        {
                            sb.append((char) c);
                            c = inStream.read();
                        }
                        response = sb.toString();
                        if (response.indexOf("OK") >= 0)
                        {
                            try
                            {
                                System.out.print("  Getting Info...");
                                outStream.write('A');
                                outStream.write('T');
                                outStream.write('+');
                                outStream.write('C');
                                outStream.write('G');
                                outStream.write('M');
                                outStream.write('M');
                                outStream.write('\r');
                                response = "";
                                c = inStream.read();
                                while (c != -1)
                                {
                                    response += (char) c;
                                    c = inStream.read();
                                }
                                System.out.println(" Found: " + response.replaceAll("\\s+OK\\s+", "").replaceAll("\n", "").replaceAll("\r", ""));
                            }
                            catch (Exception e)
                            {
                                System.out.println(_NO_DEVICE_FOUND);
                            }
                        }
                        else
                        {
                            System.out.println(_NO_DEVICE_FOUND);
                        }
                    }
                    catch (Exception e)
                    {
                        System.out.print(_NO_DEVICE_FOUND);
                        Throwable cause = e;
                        while (cause.getCause() != null)
                        {
                            cause = cause.getCause();
                        }
                        System.out.println(" (" + cause.getMessage() + ")");
                    }
                    finally
                    {
                        if (serialPort != null)
                        {
                            serialPort.close();
                        }
                    }
                }
            }
        }
        System.out.println("\nTest complete.");
    }
}
Должны в выводе получить,что то вроде:
   Trying at   9600...  Getting Info... Found:
       Trying at  14400...  no device found (
       Trying at  19200...  Getting Info... Found: E352
       Trying at  28800...  no device found
       Trying at  33600...  no device found

Так,если что то нашли,мы на пути к победе.

Дальше все проще будет.

Расскажу на примере получения входящих смс с Java кода.


import org.smslib.AGateway;
import org.smslib.AGateway.Protocols;
import org.smslib.IInboundMessageNotification;
import org.smslib.InboundMessage;
import org.smslib.InboundMessage.MessageClasses;
import org.smslib.Message.MessageTypes;
import org.smslib.Service;
import org.smslib.modem.SerialModemGateway;

import java.util.ArrayList;
import java.util.List;

public class ReadMessages
{
    public void doIt() throws Exception
    {
        List msgList;  //Объявление списка входящих смс
        InboundNotification inboundNotification = new InboundNotification();   //создание метода для оповещений и статуса входящих смс
        try
        {

            // Создаем объект нашего модема,по полученным выше данным
            SerialModemGateway gateway = new SerialModemGateway("modem", "/dev/ttyUSB2", 9600, "Huawei", "E352");
            //Задаем протокол модема,по дефолту PDU,но можно указать и TEXT
            gateway.setProtocol(Protocols.PDU);
            // Мы хотим чтобы модем работал со входящими?
            gateway.setInbound(true);
            //Мы хотим чтобы модем работал с исходящими?
            gateway.setOutbound(true);
            // Указываем SIM PIN.
            gateway.setSimPin("0000");
            // Сеттим наши оповещения
            Service.getInstance().setInboundMessageNotification(inboundNotification);
            // Добавляем сервису наш объект модема
            Service.getInstance().addGateway(gateway);
            // Стартуем сервис
            Service.getInstance().startService();
            // Можно вывести основную инфу(если нужно)
            System.out.println();
            System.out.println("Modem Information:");
            System.out.println("  Manufacturer: " + gateway.getManufacturer());
            System.out.println("  Model: " + gateway.getModel());
            System.out.println("  Serial No: " + gateway.getSerialNo());
            System.out.println("  SIM IMSI: " + gateway.getImsi());
            System.out.println("  Signal Level: " + gateway.getSignalLevel() + " dBm");
            System.out.println("  Battery Level: " + gateway.getBatteryLevel() + "%");
            System.out.println();

            msgList = new ArrayList();
            //Читаем смс
            Service.getInstance().readMessages(msgList, MessageClasses.ALL);
            for (InboundMessage msg : msgList)
                System.out.println(msg);

            System.out.println("Now Sleeping - Hit  to stop service.");
            System.in.read();

        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
        finally
        {
            Service.getInstance().stopService();
        }
    }

    public class InboundNotification implements IInboundMessageNotification
    {
        public void process(AGateway gateway, MessageTypes msgType, InboundMessage msg)
        {
            if (msgType == MessageTypes.INBOUND) System.out.println(">>> New Inbound message detected from Gateway: " + gateway.getGatewayId());
            else if (msgType == MessageTypes.STATUSREPORT) System.out.println(">>> New Inbound Status Report message detected from Gateway: " + gateway.getGatewayId());
            System.out.println(msg);
        }
    }



    public static void main(String args[])
    {
        ReadMessages app = new ReadMessages();
        try
        {
            app.doIt();
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
    }
}
Вроде в комментариях все понятно,но если что спрашиваем в комментах.

И пример с USSD(как же без него)

import org.ajwcc.pduUtils.gsm3040.PduUtils;
import org.smslib.*;
import org.smslib.AGateway.Protocols;
import org.smslib.modem.SerialModemGateway;


public class SendUSSD
{     
    public void doIt() throws Exception
    {

        USSDNotification ussdNotification = new USSDNotification();
        System.out.println("Example: Send USSD Command from a serial gsm modem.");
        System.out.println(Library.getLibraryDescription());
        System.out.println("Version: " + Library.getLibraryVersion());
        SerialModemGateway gateway = new SerialModemGateway("modem.com35", "/dev/ttyUSB2", 9600, "Huawei", "E352");
        gateway.setProtocol(Protocols.PDU);
        gateway.setInbound(true);
        gateway.setOutbound(true);
        gateway.setSimPin("0000");
        Service.getInstance().addGateway(gateway);
        Service.getInstance().setUSSDNotification(ussdNotification);
        Service.getInstance().startService();
        byte[] dataToSend = null;
        byte[] biteToSend = null;
        String stringtoSend = "*100#";
        dataToSend = PduUtils.stringToUnencodedSeptets(stringtoSend);
        biteToSend = PduUtils.encode7bitUserData(null, dataToSend);
        stringtoSend = PduUtils.bytesToPdu(biteToSend);
        System.out.println(stringtoSend);
       //  String resp = gateway.sendUSSDCommand(stringtoSend);  //вообще можно отправлять так,но у меня не заработало,поэтому ниже работает)
       String  resp = gateway.sendCustomATCommand("AT+CUSD=1,\""+stringtoSend+"\",0\r");
        System.out.println(resp);

        System.out.println("Now Sleeping - Hit  to terminate.");
        System.in.read();
        Service.getInstance().stopService();
    }

    public class USSDNotification implements IUSSDNotification
    {
        public void process(AGateway gateway, USSDResponse response) {
            System.out.println("USSD handler called from Gateway: " + gateway.getGatewayId());
            System.out.println(response);
        }
    }


    public static void main(String args[])
    {    
        SendUSSD app = new SendUSSD();
        try
        {
            app.doIt();
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
    }
}

Вот и все,не боимся автоматизировать,все что можно.

четверг, 17 января 2013 г.

Подсчет необходимого количества виртуальных пользователей.

Подсчет необходимого количества виртуальных пользователей.


Начнем с примера:
На сайте Google Analytics в средний загруженности день имеем:

  • 2000 посетителей в 60 минут
  • 10,000 просмотров страниц
  • среднее время нахождение на сайте 7 минут

Так,я хочу вывести,сколько виртуальных пользователей мне понадобится для адекватной нагрузки?
Начнем:
2000 пользователей в 1 час (60 минут), 7 минут на сайте.
60 минут / 7минут = 8.5 (пользователей в одном потоке)
2000 / 8.5 = 235 пользователей нужно всего сэмулировать.
На первый взгляд такой расчет кажется весьма логичным и применимым к нашей задаче.Каждый тестовый сценарий должен иметь среднюю продолжительность в 7 минут,чтобы отразить среднее время пребывания на сайте.То есть около 9 пользователей полностью пройдут сценарий в течении часа,т.к. наши пользователи находятся на сайте всего по 7 минут,нам не нужно проверять все 2000 пользователей одновременно.Они долго не задерживаются, поэтому, разделив 2000 пользователей по 8,5 (продолжительность визитов) получим, что около 235 пользователей.
Если представить это в виде формулы:

U = V / (60 / D)
Где:
U-это количество виртуальных пользователей (это то, что мы пытаемся выяснить)
V- это среднее количество посетителей в час
D-является средней продолжительности посетителя
60- это количество минут в часе))
Основной недостаток этого подхода,это то что мы ожидаем равномерного прибытия пользователей,что никак не гарантированно)
Вполне возможно, что из 2000 посетителей в час, 900 из них придут на  сайт в первые 10 минут, затем 400 пользователей в 40 минут, а затем 700 пользователей за последние 10 минут.
С таким раскладом наш тест,даст нам не адекватные данные.
Поэтому для надежности,обязательно смотрим логи сервера,, чтобы получить определение пика пользователей в промежуток времени.
А кому лень считать самому: используем-http://www.webperformance.com/library/tutorials/CalculateNumberOfLoadtestUsers/

четверг, 10 января 2013 г.

Кодировка ответа Sampler в Jmeter.

Кодировка ответа Sampler в Jmeter.

Иногда при работе с Jmeter,в ответах на ваши запросы он использует  неправильную кодировку.
Дело в том,что можно поставить кодировку контента(то бишь отправляемых значений),а получаемых нет.
Это можно исправить(правда способ костыльный,хотя рабочий)-используем BeanShell Jmeter.

Небольшая справка о переменных Jmeter в BeanShell для тех кто не в курсе:
  • log - (Logger) - Можно использовать для записи лога в файл.
  • ctx - (JMeterContext) - Доступ к контексту.
  • vars - ( JMeterVariables ) - Позволяет читать/записывать значения в переменные Jmeter: vars.get(key); vars.put(key,val); vars.putObject("OBJ1",new Object());
  • props - (JMeterProperties - class java.util.Properties) -собственно класс свойств из Java  props.get("START.HMS"); props.put("PROP1","1234");
  • prev - (SampleResult) - Доступ к предыдущему ответу.
  • sampleEvent (SampleEvent) доступ к текущему событию.
Собственно,если мы хотим поменять кодировку ответа на определенный запрос,то к запросу добавляем BS PostProcessor
с кодом

prev.setDataEncoding("UTF-8"); 

И все.Был рад помочь.