Pesquisar este blog

terça-feira, 11 de agosto de 2015

Python vs Java na Automação de Testes


   A muito tempo quero fazer uma comparação entre Python e Java para automação de testes. Vejo que a maioria dos treinamento são em Java para automação de testes. No entanto as outras linguagens são esquecidas como Python principalmente, é pouco falado e disseminado entre as empresas, sendo que Python é muito mais rápido a linha de aprendizado que Java.  No entanto o aprendizado em Java leva muito mais tempo e treinamento. 
   Vamos falar do ponto mais importante que é produtividade.  Fiz um pequeno teste usando a própria ferramenta do Selenium IDE pra medir a produtividade, medindo pela quantidade de linhas de código gerada pela própria ferramenta, exportando para as devidas linguagem.

Passo 01: 
Foram gravado os seguintes passos:
1. Abrir o google;
2. Pesquisar pelo assunto "Amazon";
3. Selecionar o Link e em seguida pesquisar pelo assunto "Python";
4. Selecionar o livro "Use a Cabeça! Python";
5. Clicar no botão "adicione ao carrinho".

Passo 02:
Agora vamos exportar o script gerado, seguindo as opções "Arquivo - Exportar Teste como..."
Vamos exportar com as opções abaixo:
 Python 2 / unittest / WebDriver
Java / Unit 4 / WebDriver

Passo 03:
Agora vamos abrir com o notepad++ e avaliar a quantidade de linhas de código:
Python - 55 Linhas - 2133 Caracteres
Java - 77 Linhas - 2233 Caracteres

Analisando o código gerado a ferramenta criou o método main do python pra fazer a chamada da classe e no java ela não fez isso, fazendo o mesmo a quantidade de linhas no java ia ser bem maior.

if __name__ == "__main__":
    unittest.main()


Quantidade de imports, vemos que no Python temos 7 linhas de import e no java temos 8 linhas.

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support.ui import Select
from selenium.common.exceptions import NoSuchElementException
from selenium.common.exceptions import NoAlertPresentException
import unittest, time, re


Otimizado um pouco o nosso código ficaria com 3 linhas e funcionaria de boa, não sendo necessário as outras:

from selenium import webdriver
from selenium.common.exceptions import NoSuchElementException, NoAlertPresentException
import unittest, time, re

No Python não precisamos colocar ; no final das variáveis, pelo que contei no código em java tivemos 38 ponto e vírgula, isso é desvantagem, sem falar dos parentheses. Uma característica marcada no Python é a identação do código é obrigatório que o código esteja alinhado de forma correta, isso facilita muito a manutenção do código, se torna fácil de entender a lógica e os loops, no caso do java a ferramenta fez a organização do código, mas não é assim que os desenvolvedores fazem, dificilmente você vai encontrar um código bem arrumado.

No código abaixo não sei porque a ferramenta criou driver = self.driver, podemos muito bem usar direto self.driver em todas as linhas, não precisando criar driver = self.driver, removemos com isso mais uma linha ficando com 50 linhas / 1970 Caracteres do nosso código, contra 77 linhas / 2233 Caracteres do java, aqui vemos 263 Caracteres que em python podemos ser mais produtivo que em Java. 
   É claro que é meio difícil medir a produtividade, simplesmente porque cada pessoa tem a sua velocidade e existe a IDEs como Eclipse e Pycharm que tem o code completion, Java é uma linguagem muito poderosa, mas na automação de testes não utilizamos nem 30% dela, no entanto Java é muito mais verboso e tem um tempo maior de aprendizado que Python. No meu caso, eu codifico scripts de testes em Python, posso dizer que é muito prático e rápido de codificar, no Python você pode usar o extend em mais de uma classe, no Java você não consegue isso, mas existe outras formas pra contornar em java, mas não de forma prática como no Python.
 


Código em Python:
# -*- coding: utf-8 -*-from selenium import webdriver
from selenium.common.exceptions import NoSuchElementException, NoAlertPresentException
import unittest, time, re

class SeliniumPython(unittest.TestCase):
    def setUp(self):
        self.driver = webdriver.Firefox()
        self.driver.implicitly_wait(30)
        self.base_url = "https://www.google.com.br/"        self.verificationErrors = []
        self.accept_next_alert = True        def test_selinium_python(self):
        self.driver.get(self.base_url + "/search?q=amazon&ie=utf-8&oe=utf-8&gws_rd=cr&ei=2JXKVZSXDMKXgwSSnLWYAw")
        self.driver.find_element_by_link_text("Amazon.com.br: compre livros, eBooks, e-readers Kindle e ...").click()
        self.driver.find_element_by_id("twotabsearchtextbox").click()
        self.driver.find_element_by_id("twotabsearchtextbox").clear()
        self.driver.find_element_by_id("twotabsearchtextbox").send_keys("python")
        self.driver.find_element_by_css_selector("input.nav-input").click()
        self.driver.find_element_by_xpath("//li[@id='result_3']/div/div/div/div[2]/div/a/h2").click()
        self.driver.find_element_by_id("bb_atc_button").click()
    
    def is_element_present(self, how, what):
        try: self.driver.find_element(by=how, value=what)
        except NoSuchElementException, e: return False 
        return True    
    def is_alert_present(self):
        try: self.driver.switch_to_alert()
        except NoAlertPresentException, e: return False
        return True
    def close_alert_and_get_its_text(self):
        try:
            alert = self.driver.switch_to_alert()
            alert_text = alert.text
            if self.accept_next_alert:
                alert.accept()
            else:
                alert.dismiss()
            return alert_text
        finally: self.accept_next_alert = True
    def tearDown(self):
        self.driver.quit()
        self.assertEqual([], self.verificationErrors)

if __name__ == "__main__":
    unittest.main()

Código em Java:
package com.example.tests;
import java.util.regex.Pattern;
import java.util.concurrent.TimeUnit;
import org.junit.*;
import static org.junit.Assert.*;
import static org.hamcrest.CoreMatchers.*;
import org.openqa.selenium.*;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.support.ui.Select;

public class SeleniumJava {
  private WebDriver driver;
  private String baseUrl;
  private boolean acceptNextAlert = true;
  private StringBuffer verificationErrors = new StringBuffer();

  @Before
  public void setUp() throws Exception {
    driver = new FirefoxDriver();
    baseUrl = "https://www.google.com.br/";
    driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);
  }

  @Test
  public void testSeleniumJava() throws Exception {
    driver.get(baseUrl + "/search?q=amazon&ie=utf-8&oe=utf-8&gws_rd=cr&ei=2JXKVZSXDMKXgwSSnLWYAw");
    driver.findElement(By.linkText("Amazon.com.br: compre livros, eBooks, e-readers Kindle e ...")).click();
    driver.findElement(By.id("twotabsearchtextbox")).click();
    driver.findElement(By.id("twotabsearchtextbox")).clear();
    driver.findElement(By.id("twotabsearchtextbox")).sendKeys("python");
    driver.findElement(By.cssSelector("input.nav-input")).click();
    driver.findElement(By.xpath("//li[@id='result_3']/div/div/div/div[2]/div/a/h2")).click();
    driver.findElement(By.id("bb_atc_button")).click();
  }

  @After
  public void tearDown() throws Exception {
    driver.quit();
    String verificationErrorString = verificationErrors.toString();
    if (!"".equals(verificationErrorString)) {
      fail(verificationErrorString);
    }
  }

  private boolean isElementPresent(By by) {
    try {
      driver.findElement(by);
      return true;
    } catch (NoSuchElementException e) {
      return false;
    }
  }

  private boolean isAlertPresent() {
    try {
      driver.switchTo().alert();
      return true;
      catch (NoAlertPresentException e)
      return false;
    
  }

  private String closeAlertAndGetItsText() {
    try {
      Alert alert = driver.switchTo().alert();
      String alertText = alert.getText();
      if (acceptNextAlert) {
        alert.accept();
      } else {
        alert.dismiss();
      }
      return alertText;
    } finally {
      acceptNextAlert = true;
    }
  }
}

Um comentário: