Código procedural, POO e Page Object Model para iniciantes
- #Python
- #POO
- #Selenium
Observe o script:
driver = webdriver.Chrome()
driver.get("https://shopee.com.br/")
try:
cookie_button = WebDriverWait(driver, 10).until(
EC.element_to_be_clickable((By.XPATH, '//*[@id="main"]/div/div[5]/div/div[3]/button[2]'))
)
ActionChains(driver).click(cookie_button).perform()
except Exception as e:
print(f"Erro ao rejeitar cookie: {e}")
WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.XPATH, '//*[@id="main"]/div/div[2]/div/div/div/div[2]/div/div[2]/form/div[1]/div[1]/input'))
)
email_input = driver.find_element(By.XPATH, '//*[@id="main"]/div/div[2]/div/div/div/div[2]/div/div[2]/form/div[1]/div[1]/input')
email_input.clear() # Limpar qualquer valor existente
email_input.send_keys("SEU_EMAIL")
print("Preencheu o campo de e-mail")
senha_input = driver.find_element(By.XPATH, '//*[@id="main"]/div/div[2]/div/div/div/div[2]/div/div[2]/form/div[2]/div[1]/input')
senha_input.clear() # Limpar qualquer valor existente
senha_input.send_keys("SUA_SENHA_SECRETA")
print("Preencheu o campo de senha")
try:
entrar_button = WebDriverWait(driver, 20).until(
EC.element_to_be_clickable((By.XPATH, '//*[@id="main"]/div/div[2]/div/div/div/div[2]/div/div[2]/form/button'))
)
entrar_button.click()
print("Clicou no botão 'Entrar'")
except Exception as e:
print(f"Erro ao clicar no botão 'Entrar': {e}")
O código em resumo está realizando a automação de algumas ações típicas de login em uma página, como abrir a página, rejeitar cookies, esperar pela página de login carregar, preencher campos de e-mail e senha, e clicar no botão de entrada.
Agora ...
imagine quantas linhas serão acrescentadas para lidar com popups, alertas, e se a aplicação utilizar frames ou iFrames, você precisará alternar entre eles para interagir com elementos internos… acrescentar espera explícita, ou implícita para interagir com elementos, e se a página for dinâmica os elementos carregarem em tempos diferentes… esses são pequenos desafios que podem se tornar incômodos à medida que os projetos vão ficando mais complexos. Considere ainda, que, nesse pequeno script, seja necessária a colaboração de outros programadores. Vamos concordar que muita coisa pode dar errado quando acrescentamos códigos em estruturas procedurais como esta.
Estruturas procedurais:
O primeiro script apresenta um código mais procedural, ou seja, as ações e interações são realizadas diretamente no script principal sem encapsulamento em classes e não possui métodos específicos. Nele as ações são executadas em ordem sequencial no script principal e por carecer de modularidade, torna difícil dividir o código em partes independentes e reutilizáveis. Além disso, ações e lógica de interação podem estar entrelaçadas, dificultando a compreensão e a manutenção isolada de cada parte. Atualizações ou mudanças no script podem tornar o código menos ágil, especialmente se diferentes partes do código precisarem ser manipuladas simultaneamente.
Agora observe o mesmo script com classes e métodos definidos:
class ShopeeHomePage:
def __init__(self, driver):
self.driver = driver
def accept_cookie(self):
try:
cookie_button = WebDriverWait(self.driver, 10).until(
EC.element_to_be_clickable((By.XPATH, '//*@id="main"]/div/div[5]/div/div[3]/button[2]'))
)
cookie_button.click()
except Exception as e:
print(f"Erro ao rejeitar cookie: {e}")
def navigate_to_login_page(self):
# Adicione lógica aqui para navegar para a página de login, se necessário
pass
class LoginPage:
def __init__(self, driver):
self.driver = driver
def wait_for_login_page_to_load(self):
WebDriverWait(self.driver, 10).until(
EC.presence_of_element_located((By.XPATH, '//*[@id="main"]/div/div[2]/div/div/div/div[2]/div/div[2]/form/div[1]/div[1]/input'))
)
def enter_email(self, email):
email_input = self.driver.find_element(By.XPATH, '//*[@id="main"]/div/div[2]/div/div/div/div[2]/div/div[2]/form/div[1]/div[1]/input')
email_input.clear()
email_input.send_keys(email)
def enter_password(self, password):
senha_input = self.driver.find_element(By.XPATH, '//*[@id="main"]/div/div[2]/div/div/div/div[2]/div/div[2]/form/div[2]/div[1]/input')
senha_input.clear()
senha_input.send_keys(password)
def click_login_button(self):
try:
entrar_button = WebDriverWait(self.driver, 20).until(
EC.element_to_be_clickable((By.XPATH, '//*[@id="main"]/div/div[2]/div/div/div/div[2]/div/div[2]/form/button'))
)
entrar_button.click()
except Exception as e:
print(f"Erro ao clicar no botão 'Entrar': {e}")
driver = webdriver.Chrome()
driver.get("https://shopee.com.br/")
shopee_home = ShopeeHomePage(driver)
shopee_home.accept_cookie()
login_page = LoginPage(driver)
login_page.wait_for_login_page_to_load()
login_page.enter_email("SEU_EMAIL")
login_page.enter_password("SUA_SENHA_SECRETA")
login_page.click_login_button()
Ao formatar o script criando classes (que encapsulam lógicas de interação), e chamadas de métodos (que realizam ações) temos um código orientado a objetos e quando aplicado a automação de teste web, afirmamos que este é um padrão de design Page Object Model (POM).
Nessa estrutura, as classes se transformam em page objects, e ao instanciarmos uma classe (ou criar objetos de classe) criamos objetos específicos que representam a página de aplicação. No exemplo, as classes ShopeeHomePage e LoginPage são exemplos de Page Objects. No final do script, você instancia objetos das classes ShopeeHomePage e LoginPage usando shopee_home = ShopeeHomePage(driver) e login_page = LoginPage(driver).
As instancias de classe então são usadas para chamar métodos que realizam interações específicas. Elas utilizam esses objetos para interagir com a página, chamando métodos específicos dessas classes para realizar ações como aceitar cookies, esperar pela carga da página de login e realizar o login:
login_page = LoginPage(driver)
login_page.wait_for_login_page_to_load()
login_page.enter_email("SEU_EMAIL")
login_page.enter_password("SUA_SENHA_SECRETA")
login_page.click_login_button()
Essa estrutura é uma parte fundamental da programação orientada a objetos onde você interage com objetos e invoca comportamentos específicos (métodos) associados a esses objetos:
objeto.metodo ()
Agora que nós vimos a diferença entre um código procedural e orientado a objetos, e na óptica da automação orientado a Page Object Model, concordamos que essa última abordagem facilita a organização do código e promove a reutilização de código através da criação de classes e objetos. Ainda, facilita a manutenção ao relacionar atualizações às classes (page object) e a escalabilidade, ao lidar de forma eficiente com aumento na complexidade e tamanho do projeto.
Para os programadores iniciantes é necessário apenas ‘ver’ o código e executar as boas práticas de programação, que incluem várias diretrizes que visam criar código limpo, modular e reutilizável. E ainda, mais legível, fácil de entender, manter e estender. Além de colaborativo, é claro.
Espero com esse conteúdo ter contribuído para o conhecimento de quem está começando, assim como eu.