среда, 3 января 2018 г.

Отладка Selenium тестов с помощью Jshell.

Отладка Selenium тестов с помощью Jshell.

Реебяяятааа,в общем, не буду рассказывать для чего это нужно,это и так очевидно, собственно для этой самой отладки, нам нужен этот самый jshell,который поставляется вместе с java 9.


  • Ставим jdk9
  • Добавляем переменные окружения
  • Из командной строки можем перейти непосредственно к использованию jshell


Сразу к делу.


Нам нужно добавить саму библиотеку Selenium и заимпортить нужные нам классы.
Что делаем то?
Качаем standalone отсюда.

И все,дальше по командам в командной строке:

 
/env -class-path *path to selenium.jar*

Добавляем в класспасс нашу библиотеку:
 
import org.openqa.selenium.*

Импортируем нужные нам классы и драйвер на котором будем отлаживать тесты:
 
import org.openqa.selenium.chrome.ChromeDriver;

Создаем экземпляр драйвера
 
WebDriver driver= new ChromeDriver()


Видим что то вроде этого.

И дальше пользуемся как обычно
 
driver.get("https://www.google.ru");


Вот и все.
Примерно то,что вы должны увидеть в консоли

Вроде просто.

понедельник, 20 июня 2016 г.

Custom Sampler in Jmeter

Custom Sampler in Jmeter


Иногда при создании тест планов в Jmeter, нужно кастомизировать определенные запросы.Вариантов для этого достаточно много,можно использовать BeanShellSampler,JSR223 Sampler,Java Sampler или создать свой собственный.

Наверное один из самых простых вариантов(по моему мнению) использовать Java Sampler.

Что для этого нужно сделать?

Создаем проект в нашей любимой среде разработки
Добавляем следующие jar в classpath
  • $JMETER_HOME/lib/ext/ApacheJMeter_core.jar
  • $JMETER_HOME/lib/ext/ApacheJMeter_java.jar
Создаем наш главный класс и расширяем класс AbstractJavaSamplerClient

Его методы:


 
public abstract class AbstractJavaSamplerClient implements JavaSamplerClient {
    private static final Logger log = LoggingManager.getLoggerForClass();

    public AbstractJavaSamplerClient() {
    }

    public void setupTest(JavaSamplerContext context) {
        log.debug(this.getClass().getName() + ": setupTest");
    }

    public void teardownTest(JavaSamplerContext context) {
        log.debug(this.getClass().getName() + ": teardownTest");
    }

    public Arguments getDefaultParameters() {
        return null;
    }

    protected Logger getLogger() {
        return log;
    }
}

И нам требуется переопределить метод  runTest

Если требуется переопределить какие то дефолтные параметры то делаем это вот так

 
public Arguments getDefaultParameters() {
    Arguments defaultParameters = new Arguments();
    defaultParameters.addArgument("username", "test");
    defaultParameters.addArgument("password", "test");
    return defaultParameters;
}

Метод runTest может выглядеть как то так:

 
 @Override
    public SampleResult runTest(JavaSamplerContext javaSamplerContext) {
        SampleResult result = new SampleResult();
        RequestClient requestClient = new RequestClient();
        boolean successful = true;
        String responseText = "";
        result.sampleStart();
        try {
            responseText = requestClient.sendRequest(RequestClient.METHODS.GET, "yandex.ru", null).getResponseText();
        } catch (Exception e) {
            successful = false;
            responseText = "Error with request " + requestClient.getRequestLine();
        }
        result.sampleEnd();
        result.setSuccessful(successful);
        result.setResponseData(responseText, "UTF-8");
        return result;
    }

После этого создаем jar  файл и кидаем его вот сюда $JMETER_HOME/lib/ext/


В самом Jmeter создаем новый тест план и добавляем туда Java Request,там мы сможем выбрать наш тест по имени класса 

Ну и запустив этот sampler мы получим




Вот и все.

среда, 24 февраля 2016 г.

Отправить запрос из сессии Selenium WD

Отправить запрос из сессии Selenium WD.


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

Сделать это вроде как просто,но я не нашел ничего подобного на просторах интернета.

Вот мой вариант

 
public Elements sendRequest(String host, String path, String select) {
       HttpGet get;
        Set cookieSet = driver.manage().getCookies();
        try {
            get = new HttpGet(new URIBuilder().setPath(path).build());
            CookieStore cookieStore = new BasicCookieStore();
            HttpClientContext context = HttpClientContext.create();
            RequestConfig globalConfig = RequestConfig.custom().setCookieSpec(CookieSpecs.BEST_MATCH).build();
            cookieSet.forEach(cookie -> cookieStore.addCookie(new ApacheCookie(cookie.getName(), cookie.getValue(), cookie.getPath(), cookie.getExpiry())));
            HttpResponse response = HttpClients.custom().setRedirectStrategy(new LaxRedirectStrategy()).setDefaultRequestConfig(globalConfig)
                    .setDefaultCookieStore(cookieStore).build().execute(get, context);
            Elements elements = Jsoup.parse(EntityUtils.toString(response.getEntity(), "UTF-8")).select(select);
            return elements;
        } catch (Exception e) {
                e.printStackTrace();
        }
        return null;
    }

Вроде все просто,как я и говорил)

понедельник, 9 ноября 2015 г.

JAVA RESTful Service

JAVA RESTful Service


Думаю,что никого уже нельзя удивить такими сервисами ,да и рассказывать, что это такое я не буду.(Если что погуглите)
А я просто хочу показать простой пример создания таких сервисов и клиентов к нему.(может кому нибудь это будет полезно)

Поехали.

Создадим обычный maven проект и добавим следующие зависимости

 
  
        com.sun.jersey
        jersey-server
        1.19
    


Этого достаточно чтобы поднять простой сервис с  Jersey и Jax-RS.
Выглядеть он будет достаточно тривиально,примерно следующим образом:


 
@Path("/")
public class RestService {




    @GET//метод обращения
    @Path("/helloworld")//относительный путь
    @Produces(MediaType.TEXT_PLAIN)//Мы можем указать представление типа MIME для ресурса, используя Produces аннотацию
    public String getClichedMessage() {
        return "Hello World";
    }

    @GET
    @Path("/verify")
    @Produces(MediaType.TEXT_PLAIN)
    public Response verifyRESTService(InputStream incomingData) {
        String result = "Thats ok";
        return Response.status(200).entity(result).build();
    }


    @POST
    @Path("/post")
    @Consumes(MediaType.APPLICATION_JSON)
    public Response post(String incomingData) {
        JSONObject jsonObject;
        try {
            jsonObject = new JSONObject(incomingData);
        } catch (JSONException ex) {
            return Response.status(500).entity("Error while parsing").build();
        }

        System.out.println("Data Received: " + jsonObject.toString());
        return Response.status(200).entity(jsonObject.toString()).build();
    }


    @POST
    @Path("/paramPost")
    @Consumes(MediaType.APPLICATION_JSON)
    public Response postWithParam(@FormParam("data")String incomingData) {
        JSONObject jsonObject;
        try {
            jsonObject = new JSONObject(incomingData);
        } catch (JSONException ex) {
            return Response.status(500).entity("Error while parsing").build();
        }

        System.out.println("Data Received: " + jsonObject.toString());
        return Response.status(200).entity(jsonObject.toString()).build();
    }

    public static void main(String[] args) throws IOException {
        HttpServer server = HttpServerFactory.create("http://localhost:9998/");
        server.start();
        System.out.println("Сервер запущен");
    }
}

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

Чтобы создать клиент для проверки нашего сервиса есть 2 варианта.

1.С использованием Apache Http Client


 
  public static void main(String[] argv) throws IOException {
        String jsonObject="{\n" +
                "    \"tutorials\": {\n" +
                "        \"id\": \"Apt\",\n" +
                "        \"topic\": \"REST Service\",\n" +
                "        \"description\": \"This is REST Service\"\n" +
                "    }\n" +
                "}";
        HttpClient httpClient =  HttpClientBuilder.create().build();
        HttpPost postRequest =  new HttpPost(new URIBuilder().setPath("http://localhost:9998/post").toString());
        StringEntity input = new StringEntity(jsonObject);
        input.setContentType("application/json");
        postRequest.setEntity(input);
        HttpResponse response1 = httpClient.execute(postRequest);
        System.out.println(new BasicResponseHandler().handleResponse(response1));


        HttpPost request = new HttpPost("http://localhost:9998/paramPost");
        request.setEntity(new UrlEncodedFormEntity(Collections.singletonList(new BasicNameValuePair("data", jsonObject))));
        HttpResponse response = httpClient.execute(postRequest);
        System.out.println(new BasicResponseHandler().handleResponse(response));

    }


2.Используя Jersey клиент.
Добавим в зависимости

 
  
        com.sun.jersey
        jersey-client
        1.19
    

    
        com.sun.jersey
        jersey-json
        1.19
    


И код самого клиента

 
public class ClientJersey {

    public static void main(String[] args) {
        try {
            String jsonObject="{\n" +
                    "    \"tutorials\": {\n" +
                    "        \"id\": \"Apt\",\n" +
                    "        \"topic\": \"REST Service\",\n" +
                    "        \"description\": \"This is REST Service\"\n" +
                    "    }\n" +
                    "}";
            ClientConfig clientConfig = new DefaultClientConfig();
            clientConfig.getFeatures().put(JSONConfiguration.FEATURE_POJO_MAPPING, Boolean.TRUE);
            Client clientJersey = Client.create(clientConfig);
            WebResource webResource = clientJersey.resource("http://localhost:9998/post");
            ClientResponse response = webResource.accept("application/json").type("application/json").post(ClientResponse.class, jsonObject);
            if (response.getStatus() != 200) {
                throw new RuntimeException("Failed : HTTP error code : "
                        + response.getStatus());
            }
            String output = response.getEntity(String.class);
            System.out.println("Server response .... \n");
            System.out.println(output);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}

Вот собственно и все,вот так просто.

четверг, 1 октября 2015 г.

Appium in Action

Установка Appium и тестирование мобильных приложений.


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

Ставим NodeJs,способов куча,так что это просто.

После чего надо поставить все остальное
Запустите следующую команду в окне терминала :
Шаг 1 : Затем в окне терминала выполнить следующие команды:
npm install -g grunt-cli
Шаг 2 : Затем в окне терминала выполнить следующие команды:
npm install -g appium
Шаг 3 : Затем в окне терминала выполнить следующие команды:
npm install wd
Шаг 4 : Затем в окне терминала выполнить следующие команды для запуска сервера Appium :
appium &

Есть вероятность,что пакеты не ставятся на unix системах без sudo,а ставить с ним нам нельзя((
тогда делаем так 

 
$sudo npm uninstall -g appium 
$sudo chmod -R a+w /usr/local 
$npm install -g appium

И нужно обязательно добавить путь к вашему Andoid SDK

 
export ANDROID_HOME=pathtosdk

Теперь в вашем проекте с тестами,добавляем в maven зависимости следующее


 
  
            io.appium
            java-client
            version
        

Ну и примерный запуск самого простого теста как то так :


 
public class TestAndroid {

    private AppiumDriver driver;
    private static AppiumDriverLocalService service;

    @BeforeClass
    public static void beforeClass() throws Exception{
        service = AppiumDriverLocalService.buildDefaultService();
        service.start();
    }

    @Before
    public void setUp() throws Exception {
        if (service == null || !service.isRunning())
            throw new RuntimeException("An appium server node is not started!");

        File appDir = new File("pathToapk");
        File app = new File(appDir, "app-debug.apk");
        DesiredCapabilities capabilities = new DesiredCapabilities();
        capabilities.setCapability(MobileCapabilityType.DEVICE_NAME, "Android Emulator");
        capabilities.setCapability(MobileCapabilityType.APP, app.getAbsolutePath());
        driver = new AndroidDriver(service.getUrl(), capabilities);
    }

    @After
    public void tearDown() throws Exception {
        driver.quit();
    }

    @Test
    public void findElementsTest() {
        List elements = driver.findElementsById("button");
        assertTrue(elements.size() > 0);
    }

}

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

понедельник, 3 августа 2015 г.

Многопоточность Java

CountDownLatch и Semaphore

В общем то,достаточно сжатая информация об удобных вещах в пакете java.util.concurrent,
а точнее о паре вещей оттуда.

CountDownLatch

CountDownLatch класс защелка,позволяет задержать поток(и) до тех пор,пока не выполнится определенное условие,а именно пока счетчик заданный в конструкторе не дойдет до 0.
Вообще создание объекта происходит следующим образом


 
CountDownLatch latch = new CountDownLatch(3);//по количеству потоков которых мы будем ждать
И 2 основных метода  countDown и await.
Метод await заставляет текущий поток ожидать,пока счетчик защелки не станет равен 0.
Метод countDown декрементит счетчик заданный в конструкторе и как только он дойдет до 0,потоки продолжат выполнение.

Вот пример со скачками(пример не мой,я только напихал больше комментариев по коду,ну и сократил лишнее)


 
class Race
{
    private Random rand = new Random();
    private int distance = 50;
    private List horses = Arrays.asList("Vanek","Robert","Polson","Rak");
    public void run() throws InterruptedException
    {
        System.out.println("And the horses are stepping up to the gate...");
        final CountDownLatch start = new CountDownLatch(1);//защелка для одновременного старта для всех коней,1-тк защелка для основного потока выполнения
        start.await();
        final CountDownLatch finish = new CountDownLatch(horses.size());//защелка для финиша, а здесь по количеству лошадей
        final List places = Collections.synchronizedList(new ArrayList<>());
        horses.forEach(horse -> new Thread(() -> {
            try {
                System.out.println(horse + " stepping up to the gate...");
                start.await(); // Блокируем поток,чтобы не было не одного фальстарта у наших коней
                int traveled = 0;//пройденный путь для коня
                while (traveled < distance) {
                    // каждые 0-2 секунды лошадь проходит дистанцию 0-14 пунктов
                    Thread.sleep(rand.nextInt(3) * 1000);
                    traveled += rand.nextInt(15);
                    System.out.println(horse + " advanced to " + traveled + "!");
                }
                finish.countDown();//уменьшение счетчика защелки,тк мы будем ждать именно этого момента в самой программе и когда последний конь финиширует исполнение завершится
                System.out.println(horse + " crossed the finish!");
                places.add(horse);
            } catch (InterruptedException intEx) {
                System.out.println("ABORTING RACE!!!");
                intEx.printStackTrace();
            }
        }).start());
        System.out.println("And... they're off!");
        start.countDown();//снимаем нашу защелку для старта
        finish.await();//ожидаем финиша наших скакунов
        System.out.println("And we have our winners!");
        System.out.println(places.get(0) + " took the gold...");
        System.out.println(places.get(1) + " got the silver...");
        System.out.println("and " + places.get(2) + " took home the bronze.");
    }

    public static void main(String[] args) throws InterruptedException {
        new Race().run();
    }
}

Вот как то так.

Теперь про класс Semaphore.

Он, как видно из названия,служит для ограничения количества потоков использующих определенный ресурс.
Создается объект как то так

 
Semaphore available = new Semaphore(3);//по количеству потоков которые будут активны

И 2 основных метода acquire() и release().
acquire()-Уменьшает счетчик доступных потоков(который мы задали в конструкторе) на 1.
release()-Соответственно освобождает его и увеличивает счетчик.

Небольшой пример

 
 public static void main(String[] args)
    {
        Runnable limitedCall = new Runnable() {
            final Random rand = new Random();
            final Semaphore available = new Semaphore(3);
            int count = 0;
            public void run()
            {
                int time = rand.nextInt(15);
                int num = count++;
                try
                {
                    available.acquire();//задействуем поток
                    System.out.println("Executing " +
                            "long-running action for " +time +
                            " seconds... #" + num);

                    Thread.sleep(time * 1000);
                    System.out.println("Done with #" + num + "!");
                    available.release();//после его работы освобождаем 
                }
                catch (InterruptedException intEx)
                {
                    intEx.printStackTrace();
                }
            }
        };
        for (int i=0; i<10 data-blogger-escaped-i="" data-blogger-escaped-limitedcall="" data-blogger-escaped-new="" data-blogger-escaped-pre="" data-blogger-escaped-start="" data-blogger-escaped-thread="">
Создаем 10 потоков(можно убедиться выполнив команду jstack),однако только 3 из них активны.Как только один их потоков освобождает семафор,другой занимает его место.
Вот и все.

понедельник, 18 мая 2015 г.

Java Date Format

Java Date Format

Просто справочный пост про форматы дат.
Конструктор по умолчанию использует паттерн времени и формат символов по умолчанию для текущей локализации. То есть, для русской локализации стандартным паттерном времени является паттерн "dd.MM.yy HH:mm".
Конструктор SimpleDateFormat(String pattern) принимает паттерн даты, в котором будет отдавать результат метод format(). В примере мы использовали паттерн "dd MMMM", который требует от format() вывести дату в следующем формате: "две цифры дня месяца" + "пробел" + "название месяца". В данном случае используется название месяца по умолчанию для текущей локализации, т.е., "Февраль".
Конструктор SimpleDateFormat("dd MMMM", myDateFormatSymbols ) аналогичен предыдущему за исключением того, что название месяца используется не по умолчанию, а те, которые возвращает переменная myDateFormatSymbols. В свою очередь, в переменной myDateFormatSymbols мы переопределили метод getMonths() чтобы он возвращал названия месяцев с прописной буквы и в родительном падеже.
Конструктор SimpleDateFormat("dd MMMM", Locale.ENGLISH) аналогичен конструктору SimpleDateFormat(String pattern), но использует заданную локализацию. В нашем случае это английская локализация Locale.ENGLISH.
Рассмотрим подробно параметры, принимаемые классом SimpleDateFormat в качестве паттерна даты.
СимволЧто означаетПример
Gэра (в английской локализации - AD и BC)н.э.
yгод (4-х значное число)2012
yyгод (последние 2 цифры)12
yyyyгод (4-х значное число)2012
Mномер месяца без лидирующих нулей2
MMномер месяца (с лидирующими нулями если номер месяца < 10)02
MMMчетырех буквенное сокращение месяца в русской локализации и трех буквенное - в английской (Feb)фев
MMMMполное название месяца (в английской локализации - February)Февраль
wнеделя в году без лидирующих нулей7
wwнеделя в году с лидирующими нулями07
Wнеделя в месяце без лидирующих нулей2
WWнеделя в месяце с лидирующим нулем (если это необходимо)02
Dдень в году38
dдень месяца без лидирующих нулей7
ddдень месяца с лидирующими нулями07
Fдень недели в месяце без лидирующих нулей1
FFдень недели в месяце с лидирующими нулями01
Eдень недели (сокращение)Вт
EEEEдень недели (полностью)вторник
aAM/PM указательAM
Hчасы в 24-часовом формате без лидирующих нулей6
HHчасы в 24-часовом формате с лидирующим нулем06
kколичество часов в 24-часовом формате18
Kколичество часов в 12-часовом формате6
hвремя в 12-часовом формате без лидирующих нулей6
hhвремя в 12-часовом формате с лидирующим нулем06
mминуты без лидирующих нулей32
mmминуты с лидирующим нулем32
sсекунды без лидирующих нулей11
ssсекунды с лидирующим нулем11
Sмиллисекунды109
zчасовой поясEET
Zчасовой пояс в формате RFC 822+0200
'символ экранирования для текста'Date='
''кавычка'o''clock'
Рассмотрим несколько примеров паттернов даты и времени, которые представлены в официальной документации. Русская локализация:
Паттерн даты и времениРезультат
"e;yyyy.MM.dd G 'at' HH:mm:ss z"e;2012.02.07 н.э. at 16:51:35 EET
"e;EEE, MMM d, ''yy"e;Вт, фев 7, '12
"e;h:mm a"e;4:51 PM
"e;hh 'o''clock' a, zzzz"e;04 o'clock PM, Eastern European Time
"e;K:mm a, z"e;4:51 PM, EET
"e;yyyyy.MMMMM.dd GGG hh:mm aaa"e;02012.Февраль.07 н.э. 04:51 PM
"e;EEE, d MMM yyyy HH:mm:ss Z"e;Вт, 7 фев 2012 16:51:35 +0200
"e;yyMMddHHmmssZ"e;120207165135+0200
Английская локализация:
Паттерн даты и времениРезультат
"e;yyyy.MM.dd G 'at' HH:mm:ss z"e;2012.02.07 AD at 16:55:57 EET
"e;EEE, MMM d, ''yy"e;Tue, Feb 7, '12
"e;h:mm a"e;4:55 PM
"e;hh 'o''clock' a, zzzz"e;04 o'clock PM, Eastern European Time
"e;K:mm a, z"e;4:55 PM, EET
"e;yyyyy.MMMMM.dd GGG hh:mm aaa"e;02012.February.07 AD 04:55 PM
"e;EEE, d MMM yyyy HH:mm:ss Z"e;Tue, 7 Feb 2012 16:55:57 +0200
"e;yyMMddHHmmssZ"e;120207165557+0200