Processus étape par étape et résumé de la création d'un cadre de test basé sur les données
Après avoir appris de M. Wu à créer un cadre automatisé basé sur les données, lorsque je pratiquais seul, j'ai essayé d'étendre et d'optimiser le programme simple petit à petit pour mettre en œuvre ce cadre basé sur les données.
Parlons d’abord de l’objectif de la création d’un cadre de tests automatisés :
La première consiste à réaliser le fonctionnement automatisé d'une fonction sans avoir à effectuer manuellement un travail répétitif à chaque fois.Utiliser des programmes automatisés pour remplacer le travail manuel et améliorer l'efficacité, comme l'exécution répétée de tests de régression.
La seconde consiste à encapsuler les données et les opérations sur les données, à réduire l'écriture de codes répétés et à séparer les données de test et les programmes, afin que les testeurs automatisés n'aient pas besoin de prêter trop d'attention au code.
En conservant correctement les données, vous pouvez effectuer une exécution automatisée efficace des tests, une bonne réutilisabilité et de nombreux autres avantages. . .
Permettez-moi de parler du résumé du processus après avoir construit ce framework à partir de zéro :
Implémentez d'abord la fonction à implémenter dans un fichier, puis encapsulez une certaine fonction dispersée, appelez la méthode encapsulée dans le programme principal et divisez l'ensemble du processus en plusieurs étapes.Chaque étape n'implémente qu'une seule encapsulation ou optimisation.
Tout comme pour disposer des blocs de construction, après avoir terminé un endroit, placez-vous à ce nœud et réfléchissez à ce que je peux encapsuler et optimiser ensuite, puis faites un pas en avant, puis réfléchissez à ce qui peut être optimisé sur cette base.
Jusqu'à ce que le framework de test soit construit, le processus est d'abord séparé de la structure du framework. Au lieu de penser à ce à quoi ressemblera le framework, nous pensons simplement à ce que l'encapsulation et l'optimisation peuvent être faites avec le programme existant, et comment changer pour le rendre plus utilisable.
Cela semble plus organisé, puis lorsque je réfléchis aux parties qui peuvent être extraites pour créer des packages séparés, je comparerai certaines structures de framework et sous quels types de packages ce type de package peut être placé. J'optimiserai le package et le classerai dans le même temps.
Lorsque nous encapsulons le programme et le mettons dans le fichier de configuration, nous le mettons dans le fichier de configuration. En fin de compte, vous constaterez que ce que vous obtenez de ce processus est un cadre de test.
Une fois ce processus terminé, il sera beaucoup plus facile de comprendre la fonction de chaque module à partir de l'architecture globale du framework de test, car lorsque vous l'optimiserez et l'encapsulerez à partir de zéro, vous obtiendrez enfin ces modules.
Ensuite, lorsque vous apprenez les frameworks de test pour différents types de pilotes, les principes sont fondamentalement les mêmes.
Voici le processus global de construction de ce cadre :
Tout d'abord, il est clair que ce que je veux réaliser est la fonction de connexion à la boîte aux lettres 126 et d'ajout de contacts.
Étape 1 : Si je n'utilise pas le framework et que je liste le code directement, comment puis-je y parvenir ? Essayons d'abord de terminer cela. Créez
un nouveau projet dans pycharm -dataDrivenTestPractice1.
Créez un nouveau package TestScript sous le projet.
Créer un package TestScript sous le package TestScript.
code de fichier python :
#encoding=utf-8
#author-Xia Xiaoxu
de selenium import webdriver
import time
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.common.by import By
from selenium.common.exceptions import TimeoutException, NoSuchElementException
import traceback
driver=webdriver.Firefox(executable_path='c:\\geckodriver')
driver.get('http://mail.126.com')
essayez :
wait=WebDriverWait(driver ,10,0.2)#Afficher en attente
driver.switch_to.frame(driver.find_element_by_xpath("//iframe[@id='x-URS-iframe']"))#Basculez vers l'élément frame où se trouve la zone de saisie du nom d'utilisateur et du mot de passe name=wait.until (lambda x
: x.find_element_by_xpath("//input[@placeholder='Compte de messagerie ou numéro de téléphone portable' et @name='email']")) name.send_keys('xiaxiaoxu1987') password=wait.until
(
lambda x:x.find_element_by_xpath ("//input[@placeholder='password']"))
password.send_keys('gloryroad')
submit=wait.until(lambda x:x.find_element_by_xpath("//a[@id= 'dologin']" ))
submit.click()
driver.switch_to.default_content()#L'utilisation de switch_to_default_content() dans pycharm sera barrée, et
time.sleep(5)
affirme que vous "exit" dans driver.page_source,"il n'existe pas dans page_source"
address_book_link=wait.until(lambda x:x.find_element_by_xpath("//div[text()='通讯录']"))
address_book_link.click()
#assert u"新建联系人" dans driver.page_source
add_contact_button=wait .until(lambda x:x.find_element_by_xpath("//span[text()='新建联系人']"))
add_contact_button.click()
contact_name=wait.until(lambda x:x.find_element_by_xpath("//a [@title='编辑详细姓名']/preceding-sibling::div/input"))
contact_name.send_keys(u"徐凤钗")
contact_email=wait.until(lambda x:x.find_element_by_xpath("//*[@ id='iaddress_MAIL_wrap']//input"))
contact_email.send_keys("[email protected]")
contact_is_star=wait.until(lambda x:x.find_element_by_xpath("//span[text()='Définir comme contact étoile']/preceding-sibling::span/b"))
contact_is_star.click()
contact_mobile=wait.until(lambda x:x.find_element_by_xpath("//*[@id='iaddress_TEL_wrap']//dd//input")) contact_mobile.send_keys
('18141134488')
contact_other_info=wait .until(lambda x:x.find_element_by_xpath("//textarea"))
contact_other_info.send_keys('ma femme')
contact_save_button=wait.until(lambda x:x.find_element_by_xpath("//span[.='确 定' ]"))
contact_save_button.click()
except TimeoutException, e:
# 捕获TimeoutException et
print traceback.print_exc()
except NoSuchElementException, e:
# 捕获NoSuchElementException异常
print traceback.print_exc()
except Exception, e:
#Attrapez d'autres exceptions
print résultat traceback.print_exc()
: la connexion et l'ajout de contacts sont corrects
C:\Python27\python.exe D:/test/dataDrivenTestPractice1/TestScript.py
Processus terminé avec le code de sortie 0
À ce stade, la première étape a été mise en œuvre. Voyons ensuite comment séparer le programme et les données dans ce programme.
Jetons un coup d'œil aux principales fonctions du programme :
Connectez-vous à votre messagerie-->Ouvrez la page de contact-->Cliquez sur le bouton Ajouter un contact-->Entrez les informations de contact dans la fenêtre contextuelle-->Cliquez sur le bouton Enregistrer.
Il y a aussi le noyau du data-driven -> séparation des données et des programmes
Tout d'abord, les étapes de connexion à la boîte aux lettres peuvent être extraites et empaquetées indépendamment.Le module de connexion est provisoirement désigné.
Ensuite, nous allons encapsuler la fonction de connexion et l'appeler dans le programme.
Étape 2 : extrayez la fonction de connexion, encapsulez-la et appelez-la dans le programme principal
Créer un nouveau package PageObject sous le projet
Créez un nouveau fichier python de LoginPage sous le package PageObject pour encapsuler l'opération de connexion.
Code:
#encodage=utf-8
#auteur-Xia Xiaoxu
à partir du pilote Web d'importation de sélénium
heure d'importation
à partir de selenium.webdriver.support.ui importer WebDriverWait
à partir de selenium.webdriver.common.by import Par
à partir de selenium.common.exceptions importer TimeoutException, NoSuchElementException
traçage des importations
classe LoginPage (objet):
def __init__ (soi, pilote) :
self.driver=pilote
connexion par défaut (auto):
essayer:
wait = WebDriverWait(driver, 10, 0.2) # Affichage en attente
self.driver.switch_to.frame(self.driver.find_element_by_xpath("//iframe[@id='x-URS-iframe']")) # Basculer vers l'élément frame où se trouvent les zones de saisie du nom d'utilisateur et du mot de passe
name = wait.until(lambda x: x.find_element_by_xpath("//input[@placeholder='Compte de messagerie ou numéro de téléphone mobile' et @name='email']"))
nom.send_keys('xiaxiaoxu1987')
mot de passe = wait.until(lambda x: x.find_element_by_xpath("//input[@placeholder='密码']"))
mot de passe.send_keys('gloryroad')
submit = wait.until(lambda x: x.find_element_by_xpath("//a[@id='dologin']"))
soumettre.click()
self.driver.switch_to.default_content() # Si vous utilisez switch_to_default_content() dans pycharm, il sera barré et supprimé.
temps.sommeil(5)
affirmez-vous "退出" dans self.driver.page_source, "n'existe pas dans page_source"
sauf TimeoutException, e :
#Catch TimeoutExceptionexception
imprimer traceback.print_exc()
sauf NoSuchElementException, e :
#Catch NoSuchElementExceptionexception
imprimer traceback.print_exc()
sauf exception, e :
#Attrapez d'autres exceptions
imprimer traceback.print_exc()
si __name__=="__main__":
driver=webdriver.Firefox(executable_path='c:\\geckodriver')
driver.get("http:\\mail.126.com")
login = Page de connexion (pilote)
Connexion Connexion()
Résultat : connexion réussie
C:\Python27\python.exe D:/test/dataDrivenTestPractice1/PageObject/Login_page.py
Processus terminé avec le code de sortie 0
À ce stade, la fonction de connexion est encapsulée. Ensuite, modifiez le programme principal et appelez LoginPage.
TestScript.py :
#encodage=utf-8
#auteur-Xia Xiaoxu
à partir du pilote Web d'importation de sélénium
heure d'importation
à partir de selenium.webdriver.support.ui importer WebDriverWait
à partir de selenium.webdriver.common.by import Par
à partir de selenium.common.exceptions importer TimeoutException, NoSuchElementException
traçage des importations
à partir de l'importation PageObject.Login_Page *
driver=webdriver.Firefox(executable_path='c:\\geckodriver')
driver.get('http://mail.126.com')
lp = Page de connexion (pilote)
wait = WebDriverWait(driver, 10, 0.2) # Affichage en attente
essayer:
lp.login()
address_book_link=wait.until(lambda x:x.find_element_by_xpath("//div[text()='通讯录']"))
adresse_book_link.click()
#affirmez que vous êtes "Nouveau contact" dans driver.page_source
add_contact_button=wait.until(lambda x:x.find_element_by_xpath("//span[text()='New Contact']"))
add_contact_button.click()
contact_name=wait.until(lambda x:x.find_element_by_xpath("//a[@title='Modifier le nom détaillé']/preceding-sibling::div/input"))
contact_name.send_keys(u"徐凤钗")
contact_email=wait.until(lambda x:x.find_element_by_xpath("//*[@id='iaddress_MAIL_wrap']//input"))
contact_email.send_keys("[email protected]")
contact_is_star=wait.until(lambda x:x.find_element_by_xpath("//span[text()='Définir comme contact étoile']/preceding-sibling::span/b"))
contact_is_star.click()
contact_mobile=wait.until(lambda x:x.find_element_by_xpath("//*[@id='iaddress_TEL_wrap']//dd//input"))
contact_mobile.send_keys('18141134488')
contact_other_info=wait.until(lambda x:x.find_element_by_xpath("//textarea"))
contact_other_info.send_keys('ma femme')
contact_save_button=wait.until(lambda x:x.find_element_by_xpath("//span[.='确 定']"))
contact_save_button.click()
sauf TimeoutException, e :
#Catch TimeoutExceptionexception
imprimer traceback.print_exc()
sauf NoSuchElementException, e :
#Catch NoSuchElementExceptionexception
imprimer traceback.print_exc()
sauf exception, e :
#Attrapez d'autres exceptions
imprimer traceback.print_exc()
Résultat : Succès
C:\Python27\python.exe D:/test/dataDrivenTestPractice1/TestScript/TestScript.py
Processus terminé avec le code de sortie 0
Du point de vue du programme principal, l'action d'ajouter des contacts peut également être encapsulée. Encapsulons d'abord cette partie. S'il y a des problèmes plus tard, nous pouvons revenir en arrière et le déduire. Faites-le d'abord selon cette idée, puis faites encore une fois.
Étape 3 : Encapsuler la fonction d'ajout de contacts
Créez un nouveau fichier python AddressBook sous le package PageObject
CodeAddressBook.py :
#encodage=utf-8
#auteur-Xia Xiaoxu
à partir du pilote Web d'importation de sélénium
heure d'importation
à partir de selenium.webdriver.support.ui importer WebDriverWait
à partir de selenium.webdriver.common.by import Par
à partir de selenium.common.exceptions importer TimeoutException, NoSuchElementException
traçage des importations
à partir de l'importation PageObject.Login_Page *
classe Carnet d'adresses (objet):
def __init__ (soi, pilote) :
self.driver=pilote
def add_contact(soi) :
essayer:
wait = WebDriverWait(self.driver, 10, 0.2) # Affichage en attente
address_book_link = wait.until(lambda x: x.find_element_by_xpath("//div[text()='通讯录']"))
adresse_book_link.click()
# affirmez votre "Nouveau contact" dans driver.page_source
add_contact_button = wait.until(lambda x: x.find_element_by_xpath("//span[text()='New Contact']"))
add_contact_button.click()
nom_contact = attendre.jusqu'à(
lambda x : x.find_element_by_xpath("//a[@title='Modifier le nom détaillé']/preceding-sibling::div/input"))
contact_name.send_keys(u"徐凤钗")
contact_email = wait.until(lambda x: x.find_element_by_xpath("//*[@id='iaddress_MAIL_wrap']//input"))
contact_email.send_keys("[email protected]")
contact_is_star = attendre.jusqu'à(
lambda x : x.find_element_by_xpath("//span[text()='Set as star contact']/preceding-sibling::span/b"))
contact_is_star.click()
contact_mobile = wait.until(lambda x: x.find_element_by_xpath("//*[@id='iaddress_TEL_wrap']//dd//input"))
contact_mobile.send_keys('18141134488')
contact_other_info = wait.until(lambda x: x.find_element_by_xpath("//textarea"))
contact_other_info.send_keys('ma femme')
contact_save_button = wait.until(lambda x: x.find_element_by_xpath("//span[.='确 定']"))
contact_save_button.click()
sauf TimeoutException, e :
#Catch TimeoutExceptionexception
imprimer traceback.print_exc()
sauf NoSuchElementException, e :
#Catch NoSuchElementExceptionexception
imprimer traceback.print_exc()
sauf exception, e :
#Attrapez d'autres exceptions
imprimer traceback.print_exc()
si __name__=="__main__":
driver=webdriver.Firefox(executable_path='c:\\geckodriver')
driver.get('http://mail.126.com')
lp = Page de connexion (pilote)
lp.login()
ab=Carnet d'adresses (pilote)
ab.add_contact()
Résultat : Succès
C:\Python27\python.exe D:/test/dataDrivenTestPractice1/PageObject/AddressBook.py
Processus terminé avec le code de sortie 0
À ce stade, la fonction d'ajout de contacts est à peu près encapsulée. Appelez-la maintenant dans le programme principal.
TestScript.py :
#encodage=utf-8
#auteur-Xia Xiaoxu
à partir du pilote Web d'importation de sélénium
heure d'importation
à partir de selenium.webdriver.support.ui importer WebDriverWait
à partir de selenium.webdriver.common.by import Par
à partir de selenium.common.exceptions importer TimeoutException, NoSuchElementException
traçage des importations
à partir de l'importation PageObject.Login_Page *
à partir de l'importation PageObject.AddressBook *
driver=webdriver.Firefox(executable_path='c:\\geckodriver')
driver.get('http://mail.126.com')
loginPage = Page de connexion (pilote)
adresseBook = Carnet d'adresses (pilote)
connexionPage.login()
carnet d'adresses.add_contact()
Résultat : Succès
C:\Python27\python.exe D:/test/dataDrivenTestPractice1/TestScript/TestScript.py
Processus terminé avec le code de sortie 0
À ce stade, les deux fonctions du programme - se connecter et ajouter des contacts - ont été grossièrement encapsulées. Vous pouvez appeler la fonction directement dans le programme principal. Passons en revue les principales fonctions du programme :
Connectez-vous à votre messagerie-->Ouvrez la page de contact-->Cliquez sur le bouton Ajouter un contact-->Entrez les informations de contact dans la fenêtre contextuelle-->Cliquez sur le bouton Enregistrer. Il y a aussi le noyau du data-driven -> séparation des données et des programmes
Ensuite, je veux essayer d’extraire une partie des données. Voyons comment séparer ces données ?
Du point de vue du programme, la partie qui appelle les données se trouve dans les deux modules qui viennent d'être encapsulés, Login_Page et AddressBook. Voyons comment le programme utilise les données.
Page de connexion:
Carnet d'adresses:
Lors de l'encapsulation de ces deux fonctions, aucun paramètre n'est laissé de côté, et ils sont écrits directement dans la fonction. C'est évidemment relativement faible, alors comment faire ? Essayons de remplacer les données qui doivent être appelées dans la fonction par des paramètres, puis transmettons les paramètres lors de l'appel.
Modifions d'abord la fonction de connexion et voyons comment la modifier pour utiliser les paramètres. À ce moment-là, je suis soudainement devenu confus. Avec autant de données différentes, il n'y a aucun moyen d'utiliser des paramètres. . .
Si vous souhaitez utiliser le transfert de paramètres, vous devez diviser la fonction de connexion. Vous pouvez voir qu'il existe plusieurs parties de la fonction de connexion qui peuvent être encapsulées. Par exemple, recherchez la fonction de l'élément frame, recherchez la fonction du nom d'utilisateur élément de la zone de saisie, puis recherchez le seul Dans la fonction de l'élément, vous pouvez transmettre des données aux paramètres de recherche.
Étape 4 : Encapsuler la fonction de recherche d'éléments
Modifier LoginPage.py :
#encodage=utf-8
#auteur-Xia Xiaoxu
à partir du pilote Web d'importation de sélénium
heure d'importation
à partir de selenium.webdriver.support.ui importer WebDriverWait
à partir de selenium.webdriver.common.by import Par
à partir de selenium.common.exceptions importer TimeoutException, NoSuchElementException
traçage des importations
classe LoginPage (objet):
def __init__ (soi, pilote) :
self.driver=pilote
self.wait = WebDriverWait(self.driver, 10, 0.2) # Afficher l'attente
def getFrame(self,locateType,locateExpression) :
frame=self.wait.until(lambda x: x.find_element(by=locateType,value=locateExpression))#"//iframe[@id='x-URS-iframe']"
trame de retour
def getUserName(self,locateType,locateExpression) :
userName=self.wait.until(lambda x: x.find_element(by=locateType,value=locateExpression))#"//input[@placeholder='Compte de messagerie ou numéro de téléphone mobile' et @name='email']"
renvoyer le nom d'utilisateur
def getPassword(self,locateType,locateExpression) :
password=self.wait.until(lambda x: x.find_element(by=locateType,value=locateExpression))#"//input[@placeholder='密码']"
retourner le mot de passe
def getLoginButton(self,locateType,locateExpression) :
loginButton=self.wait.until(lambda x: x.find_element(by=locateType,value=locateExpression))#"//a[@id='dologin']"
retourner le bouton de connexion
si __name__=="__main__":
driver=webdriver.Firefox(executable_path='c:\\geckodriver')
driver.get("http:\\mail.126.com")
lp = Page de connexion (pilote)
driver.switch_to.frame(lp.getFrame("xpath","//iframe[@id='x-URS-iframe']"))
temps.sommeil(2)
lp.getUserName("xpath","//input[@placeholder='compte de messagerie ou numéro de téléphone mobile' et @name='email']").clear()
lp.getUserName("xpath","//input[@placeholder='compte de messagerie ou numéro de téléphone portable' et @name='email']").send_keys("xiaxiaoxu1987")
lp.getPassword("xpath","//input[@placeholder='密码']").send_keys("gloryroad")
lp.getLoginButton("xpath","//a[@id='dologin']").click()
driver.switch_to.default_content()
temps.sommeil(5)
affirmez que vous "退出" dans driver.page_source, "n'existe pas dans page_source"
Résultat : connexion réussie
À ce stade, bien que les données soient transmises en paramètre à chaque fonction qui recherche des éléments, il existe un problème.
Lors d'un appel, vous devez saisir manuellement les données nécessaires pour trouver l'élément, ce qui est plus gênant. Si vous saisissez une mauvaise lettre, l'élément ne sera pas trouvé. Comment faire ?
Il doit être réencapsulé, mettre les données dans un fichier, puis encapsuler la méthode pour lire les données du fichier. De cette façon, vous devez créer un fichier de configuration pour stocker les données, puis créer un nouveau python fichier pour encapsuler la méthode de lecture du fichier de configuration.
Étape 5 : placez les données dans le fichier de configuration, puis encapsulez la méthode pour lire les données du fichier
Créez un nouveau package appelé Conf sous le projet (utilisé pour stocker les fichiers liés à la configuration) :
Créez un nouveau fichier sous le package Conf : PageObjectRepository.ini
PageObjectRepository.ini :
[126mail_login]
login_page.frame=id>x-URS-iframe
login_page.username=xpath>//input[@name='email']
login_page.password=xpath>//input[@name='password']
login_page.loginbutton=id>dologin
[126mail_homepage]
home_page.addressbook=xpath>//div[text()='Carnet d'adresses']
[126mail_addcontactspage]
addcontacts_page.createcontactsbtn=xpath>//span[text()='Nouveau contact']
addcontacts_page.contactpersonname=xpath>//a[@title='Modifier le nom détaillé']/preceding-sibling::div/input
addcontacts_page.contactpersonemail=xpath>//*[@id='iaddress_MAIL_wrap']//input
addcontacts_page.starcontacts=xpath>//span[text()='Définir comme contact étoile']/preceding-sibling::span/b
addcontacts_page.contactpersonmobile=xpath>//*[@id='iaddress_TEL_wrap']//dd//input
addcontacts_page.contactpersoncomment=xpath>//textarea
addcontacts_page.savecontaceperson=xpath>//span[.='OK']
Créez un nouveau package Util sous le projet. Ce package est généralement utilisé pour stocker des classes d'outils, telles que la lecture de fichiers de configuration, la recherche de méthodes d'éléments, les classes d'opérations Excel, les classes de temps, les méthodes et opérations de journalisation, les captures d'écran, les modèles de rapport, etc.
Créez un nouveau fichier python sous le package Util : ParsePageObjectRepository.py pour encapsuler la classe de lecture des fichiers de configuration.
#encodage=utf-8
#auteur-Xia Xiaoxu
à partir de ConfigParser importer ConfigParser
classe ParsePageObjectRepositoryConfig (objet) :
def __init__(self,config_path) :
self.cf=ConfigParser()#Générer l'analyseur
self.cf.read(config_path)
def getItemSection(self,sectionName) :
imprimer self.cf.items(sectionName)
retourner dict(self.cf.items(sectionName))
def getOptionValue(self,sectionName,optionName):#Renvoyer un dictionnaire
print self.cf.get(sectionName,optionName)
return self.cf.get(sectionName,optionName)
si __name__=='__main__' :
pp=ParsePageObjectRepositoryConfig( "D:\\test\\dataDrivenTestPractice1\\Conf\\PageObjectRepository.ini" )
imprimer pp.getItemSection("126mail_login")
imprimer pp.getOptionValue("126mail_login","login_page.username")
Résultat : OK
C:\Python27\python.exe D:/test/dataDrivenTestPractice1/Util/ParsePageObjectRepository.py
[('login_page.frame', 'id>x-URS-iframe'), ('login_page.username', "xpath>//input[@name='email']"), ('login_page.password', "xpath>//input[@name='password']"), ('login_page.loginbutton', 'id>dologin')]
{'login_page.loginbutton' : 'id>dologin', 'login_page.username' : "xpath>//input[@name='email']", 'login_page.frame' : 'id>x-URS-iframe' , 'login_page.password' : "xpath>//input[@name='password']"}
xpath>//input[@name='email']
xpath>//input[@name='email']
Processus terminé avec le code de sortie 0
Vous pouvez voir que lorsque la fonction de lecture est appelée dans le code de test, le chemin d'accès au fichier de configuration doit être saisi manuellement dans le paramètre. Il s'agit d'un caractère long. Si le chemin est modifié, il doit être modifié ici. Puisqu'il est tout encapsulé ici, il est facile de le modifier ici. Soyez diligent et configurez le chemin dans une variable.
Généralement, la variable stockant le chemin du fichier doit être placée dans le fichier var.py sous le package ProjectVar. Après cela, les chemins de tous les fichiers de configuration sont conservés sous forme de variables dans ce fichier. Le chemin relatif est utilisé pour obtenir le chemin, qui est plus sécurisé.
Étape 6 : utilisez des variables pour stocker le chemin d'accès au fichier de configuration
Créer un nouveau package ProjectVar sous le projet
Créez un nouveau fichier python de var.py sous le package ProjectVar
var.py :
#encodage=utf-8
#auteur-Xia Xiaoxu
importez-nous
#Obtenir le chemin absolu du répertoire où se trouve le projet
project_path=os.path.dirname(os.path.dirname(__file__))
#Obtenir le chemin absolu du fichier de bibliothèque d'objets de page
page_object_repository_path=project_path.decode("utf-8")+u"/conf/PageObjectRepository.ini"
si __name__=='__main__' :
#Tester le code
imprimer "chemin_projet :", chemin_projet
imprimer "page_object_repository_path :",page_object_repository_path
imprimer os.path.exists (project_path)
imprimer os.path.exists (page_object_repository_path)
résultat:
C:\Python27\python.exe D:/test/dataDrivenTestPractice1/ProjectVar/var.py
chemin_projet : D:/test/dataDrivenTestPractice1
chemin_page_object_repository : D:/test/dataDrivenTestPractice1/conf/PageObjectRepository.ini
Vrai
Vrai
Processus terminé avec le code de sortie 0
Testez maintenant l'exécution de la lecture du fichier de configuration dans ParsePageObjectRepository.py
ParsePageObjectRepository.py:
#encodage=utf-8
#auteur-Xia Xiaoxu
à partir de ConfigParser importer ConfigParser
à partir de ProjectVar.var import page_object_repository_path#Nouvellement ajouté
classe ParsePageObjectRepositoryConfig (objet) :
def __init__(self):#Suppression du paramètre config_path
self.cf=ConfigParser()#Générer l'analyseur
self.cf.read(page_object_repository_path)#Remplacer directement par des variables
def getItemSection(self,sectionName) :
imprimer self.cf.items(sectionName)
retourner dict(self.cf.items(sectionName))
def getOptionValue(self,sectionName,optionName):#Renvoyer un dictionnaire
print self.cf.get(sectionName,optionName)
return self.cf.get(sectionName,optionName)
si __name__=='__main__' :
pp=ParsePageObjectRepositoryConfig()#La variable d'adresse du fichier de configuration a été initialisée dans le constructeur
imprimer pp.getItemSection("126mail_login")
imprimer pp.getOptionValue("126mail_login","login_page.username")
Résultat : OK
C:\Python27\python.exe D:/test/dataDrivenTestPractice1/Util/ParsePageObjectRepository.py
[('login_page.frame', 'id>x-URS-iframe'), ('login_page.username', "xpath>//input[@name='email']"), ('login_page.password', "xpath>//input[@name='password']"), ('login_page.loginbutton', 'id>dologin')]
{'login_page.loginbutton' : 'id>dologin', 'login_page.username' : "xpath>//input[@name='email']", 'login_page.frame' : 'id>x-URS-iframe' , 'login_page.password' : "xpath>//input[@name='password']"}
xpath>//input[@name='email']
xpath>//input[@name='email']
Ensuite, corrigez les appels dans le fichier login.py et remplacez tous les paramètres qui doivent être saisis manuellement en lisant le fichier de configuration.
Modifier login.py :
#encodage=utf-8
#auteur-Xia Xiaoxu
à partir du pilote Web d'importation de sélénium
heure d'importation
à partir de selenium.webdriver.support.ui importer WebDriverWait
à partir de selenium.webdriver.common.by import Par
from selenium.common.exceptions import TimeoutException, NoSuchElementException
import traceback
from Util.ParsePageObjectRepository import *#新加
from ProjectVar.var import *#新加
class LoginPage(object):
def __init__(self,driver):
self.driver=driver
self.parse_config_file=ParsePageObjectRepositoryConfig()#新加,获取配置文件信息
self.login_page_items=self.parse_config_file.getItemSection("126mail_login")#新加
print "self.login_page_items:",self.login_page_items
self.wait = WebDriverWait(self.driver, 10, 0.2) # 显示等待
def getFrame(self):#参数去掉,在里面处理
locateType,locateExpression=self.login_page_items['login_page.frame'].split('>')#id>x-URS-iframe
frame=self.wait.until(lambda x: x.find_element(by=locateType,value=locateExpression))#"//iframe[@id='x-URS-iframe']"
trame de retour
def getUserName(self): #Supprimez les paramètres et traitez-les à l'intérieur
LocateType, LocateExpression = self.login_page_items['login_page.username'].split('>')#xpath>//input[@name='email']
userName=self.wait.until(lambda x: x.find_element(by=locateType,value=locateExpression))#"//input[@placeholder='Compte de messagerie ou numéro de téléphone mobile' et @name='email']"
renvoyer le nom d'utilisateur
def getPassword(self): #Supprimez les paramètres et traitez-les à l'intérieur
LocateType, LocateExpression = self.login_page_items['login_page.password'].split('>')#xpath>//input[@name='password']
password=self.wait.until(lambda x: x.find_element(by=locateType,value=locateExpression))#"//input[@placeholder='密码']"
retourner le mot de passe
def getLoginButton(self): #Supprimez les paramètres et traitez-les à l'intérieur
LocateType, LocateExpression = self.login_page_items['login_page.loginbutton'].split('>') #id>dologin
loginButton=self.wait.until(lambda x: x.find_element(by=locateType,value=locateExpression))#"//a[@id='dologin']"
retourner le bouton de connexion
si __name__=="__main__":
driver=webdriver.Firefox(executable_path='c:\\geckodriver')
driver.get("http:\\mail.126.com")
lp = Page de connexion (pilote)
driver.switch_to.frame(lp.getFrame())
temps.sommeil(2)
lp.getUserName().clear()
lp.getUserName().send_keys("xiaxiaoxu1987")
lp.getPassword().send_keys("gloryroad")
lp.getLoginButton().click()
driver.switch_to.default_content()
temps.sommeil(5)
affirmez que vous "退出" dans driver.page_source, "n'existe pas dans page_source"
Jusqu'à présent, nous avons encapsulé beaucoup de choses et mis les données de connexion dans le fichier de configuration pour les lire. Cependant, il reste encore beaucoup de chemin à parcourir avant la perfection, mais cela n'a pas d'importance. Tant que nous avons une vision claire idée, la perfection n'est qu'une question de temps. Voyons maintenant s'il y a des problèmes avec ce framework qui doivent être optimisés.
Vous pouvez constater que les deux points suivants peuvent être optimisés :
1-Dans la méthode d'obtention des éléments de la page de connexion dans le fichier login_page.py, les étapes suivantes pour rechercher des éléments peuvent être encapsulées,
self.wait.until(lambda x: x.find_element(by=locateType,value=locateExpression)), il n'est pas nécessaire d'écrire ceci dans chaque méthode de recherche d'éléments, et cette étape de recherche d'éléments est en cours d'ajout de contacts au compte Il sera également utilisé dans les fonctions.Il sera beaucoup plus pratique d'encapsuler la méthode de recherche d'éléments.
2-Deuxièmement, lors de l'exécution de l'opération de connexion, nous saisissons manuellement les informations de nom d'utilisateur et de mot de passe. Cela peut également être encapsulé. Comment l'encapsuler ? Chaque méthode du fichier login.py initial obtient les informations de connexion. Pour les éléments requis, nous appelez manuellement ces méthodes lors de l'exécution de l'opération de connexion. Après avoir obtenu les éléments, entrez des caractères ou cliquez pour terminer l'opération de connexion. Ces étapes peuvent ensuite être effectuées dans un autre fichier. L'encapsulation, pour parler franchement, consiste à encapsuler la méthode d'obtention de chaque élément dans login_page pour réaliser la fonction de connexion. Vous n'avez pas besoin d'organiser vous-même les méthodes dispersées à chaque fois. Mettez-le dans une boîte. Le nom de la boîte est login. À chaque fois, exécutez simplement cette boîte, ne vous inquiétez pas les détails à l'intérieur, tous les emballages sont les mêmes.
Étape 7 : encapsuler la fonction de recherche d'éléments et encapsuler davantage la fonction de connexion
Comme vous pouvez le voir dans la structure initiale du cadre, la méthode de recherche d'éléments peut être placée dans le package Util.
Créez un nouveau fichier ObjectMap.py dans le package Util
ObjectMap.py :
#encodage=utf-8
#auteur-Xia Xiaoxu
à partir de selenium.webdriver.support.ui importer WebDriverWait
#Obtenir un objet à un seul élément
def getElement(pilote,locateType,locateExpression) :
essayer:
element=WebDriverWait(driver,10).until(lambda x:x.find_element(by=locateType,value=locateExpression))
élément de retour
sauf exception,e :
élever e
#Obtenez plusieurs objets d'élément de page identiques et renvoyez-les sous forme de liste
def getElements(pilote,locateType,locatorExpression) :
essayer:
elements=WebDriverWait(driver,5).until(lambda x:x.find_elements(by=locateType,value=locateExpression))
éléments de retour
sauf exception,e :
élever e
si __name__=="__main__":
#Tester le code
à partir du pilote Web d'importation de sélénium
driver=webdriver.Firefox(executable_path='c:\\geckodriver')
driver.get('http://www.baidu.com')
searchBox=getElement(driver,"xpath","//input[@id='kw']")
pilote.quit()
Résultat : OK
C:\Python27\python.exe D:/test/dataDrivenTestPractice1/Util/ObjectMap.py
Processus terminé avec le code de sortie 0
À ce stade, la méthode de recherche d'éléments est encapsulée. Modifions Login_Page.py pour appeler la méthode ObjectMap afin d'implémenter chaque méthode de recherche d'éléments et encapsulons l'action de connexion.
Login_page.py :
#encodage=utf-8
#auteur-Xia Xiaoxu
à partir du pilote Web d'importation de sélénium
heure d'importation
à partir de selenium.webdriver.support.ui importer WebDriverWait
à partir de selenium.webdriver.common.by import Par
à partir de selenium.common.exceptions importer TimeoutException, NoSuchElementException
traçage des importations
à partir de l'importation de Util.ParsePageObjectRepository *
à partir de l'importation ProjectVar.var *
à partir de l'importation Util.ObjectMap *
classe LoginPage (objet):
def __init__ (soi, pilote) :
self.driver=pilote
self.parse_config_file=ParsePageObjectRepositoryConfig()
self.login_page_items=self.parse_config_file.getItemSection("126mail_login")
imprimer "self.login_page_items :",self.login_page_items
self.wait = WebDriverWait(self.driver, 10, 0.2) # Afficher l'attente
def getFrame(soi) :
LocateType,locateExpression=self.login_page_items['login_page.frame'].split('>')#id>x-URS-iframe
frame=getElement(self.driver,locateType,locateExpression)#"//iframe[@id='x-URS-iframe']"
trame de retour
def getUserName (soi) :
LocateType, LocateExpression = self.login_page_items['login_page.username'].split('>')#xpath>//input[@name='email']
userName=getElement(self.driver,locateType,locateExpression)#"//input[@placeholder='Compte de messagerie ou numéro de téléphone portable' et @name='email']"
renvoyer le nom d'utilisateur
def getPassword(soi) :
LocateType, LocateExpression = self.login_page_items['login_page.password'].split('>')#xpath>//input[@name='password']
password=getElement(self.driver,locateType,locateExpression)#"//input[@placeholder='密码']"
retourner le mot de passe
def getLoginButton (soi) :
LocateType, LocateExpression = self.login_page_items['login_page.loginbutton'].split('>') #id>dologin
loginButton=getElement(self.driver,locateType,locateExpression)#"//a[@id='dologin']"
retourner le bouton de connexion
connexion par défaut (auto):
self.driver.switch_to.frame(self.getFrame())
self.getUserName().clear()
self.getUserName().send_keys("xiaxiaoxu1987")
self.getPassword().send_keys("gloryroad")
self.getLoginButton().click()
if __name__=="__main__":
#测试代码
driver=webdriver.Firefox(executable_path='c:\\geckodriver')
driver.get("http:\\mail.126.com")
lp=LoginPage(driver)
lp.login()
结果:可以登录
C:\Python27\python.exe D:/test/dataDrivenTestPractice1/PageObject/Login_Page.py
self.login_page_items: {'login_page.loginbutton': 'id>dologin', 'login_page.username': "xpath>//input[@name='email']", 'login_page.frame': 'id>x-URS-iframe', 'login_page.password': "xpath>//input[@name='password']"}
Process finished with exit code 0
下面我们把login函数的封装从Login_page.py中挪出去,作为单独的一个文件存在,把方法和调用分隔开,以后如果有变动,修改login_page.py就可以了。
步骤8—单独封装login方法
在工程下新建一个Action的包
在Action包下新建login.py
Login.py:
#encoding=utf-8
#author-夏晓旭
from PageObject.Login_Page import *
from selenium import webdriver
def login (pilote, nom d'utilisateur, mot de passe) :
lp = Page de connexion (pilote)
driver.switch_to.frame(lp.getFrame())
lp.getUserName().clear()
lp.getUserName().send_keys(nom d'utilisateur)
lp.getPassword().send_keys(mot de passe)
lp.getLoginButton().click()
si __name__=='__main__' :
#Tester le code
driver=webdriver.Firefox(executable_path='c:\\geckodriver')
driver.get("http://mail.126.com")
connexion (pilote, "xiaxiaoxu1987", "gloryroad")
Résultat : connexion réussie
C:\Python27\python.exe D:/test/dataDrivenTestPractice1/Action/login.py
self.login_page_items : {'login_page.loginbutton' : 'id>dologin', 'login_page.username' : "xpath>//input[@name='email']", 'login_page.frame' : 'id>x- URS-iframe', 'login_page.password' : "xpath>//input[@name='password']"}
Processus terminé avec le code de sortie 0
À ce stade, la fonction de connexion est essentiellement encapsulée et les données et le programme sont séparés. Jetons un coup d'œil à l'encapsulation de l'ajout de contacts pour réaliser la séparation des données et du programme étape par étape. Les opérations d'ajout de contacts ont été mises en AddressBook.py avant. , mais la situation est la même que celle de login_page.py au début. L'opération de recherche d'éléments et la lecture des données du fichier de configuration n'ont pas encore été effectuées. Commençons par cela.
Étape 9 : Encapsuler l'opération d'ajout de contact
Idée:
Dans AddressBook.py, encapsulez chaque élément nécessaire pour ajouter une page de contact dans une méthode, recherchez les données XPath requises pour chaque élément et placez-les dans le fichier de configuration, puis utilisez une fonction pour appeler les méthodes de ces éléments pour implémenter les caractères d'entrée. ou cliquez sur les opérations. Implémentez la fonction d'ajout de contacts
Carnet d'adresses.py:
#encodage=utf-8
#auteur-Xia Xiaoxu
à partir du pilote Web d'importation de sélénium
heure d'importation
à partir de selenium.webdriver.support.ui importer WebDriverWait
à partir de selenium.webdriver.common.by import Par
à partir de selenium.common.exceptions importer TimeoutException, NoSuchElementException
traçage des importations
à partir de l'importation PageObject.Login_Page *
à partir de l'importation Action.login *
classe Carnet d'adresses (objet):
def __init__ (soi, pilote) :
self.driver=pilote
self.parse_config_file=ParsePageObjectRepositoryConfig()
self.address_book_page=self.parse_config_file.getItemsFromSection("126mail_homepage")
imprimer "self.address_book_page:",self.address_book_page
self.address_book_page_itmes=self.parse_config_file.getItemsFromSection("126mail_addcontactspage")
imprimer "self.address_book_page_itmes:", self.address_book_page_itmes
def adresse_book_link(soi) :
LocateType,locateExpression = self.address_book_page['home_page.addressbook'].split(">")
imprimer le type de localisation, localiser l'expression
return getElement(self.driver,"xpath","//div[text()='Carnet d'adresses']")
def add_contact_button(soi) :
LocateType,locateExpression=self.address_book_page_itmes['addcontacts_page.createcontactsbtn'].split(">")
imprimer le type de localisation, localiser l'expression
retourner getElement(self.driver,locateType,locateExpression)
def nom_contact (soi) :
LocateType,locateExpression=self.address_book_page_itmes['addcontacts_page.contactpersonname'].split(">")
imprimer le type de localisation, localiser l'expression
retourner getElement (self.driver, LocateType, LocateExpression)
def contact_email(soi) :
LocateType, LocateExpression = self.address_book_page_itmes['addcontacts_page.contactpersonemail'].split(">")
imprimer le type de localisation, localiser l'expression
retourner getElement (self.driver, LocateType, LocateExpression)
def contact_is_star(soi) :
LocateType, LocateExpression = self.address_book_page_itmes['addcontacts_page.starcontacts'].split(">")
imprimer le type de localisation, localiser l'expression
retourner getElement (self.driver, LocateType, LocateExpression)
def contact_mobile(soi) :
LocateType, LocateExpression = self.address_book_page_itmes['addcontacts_page.contactpersonmobile'].split(">")
imprimer le type de localisation, localiser l'expression
retourner getElement (self.driver, LocateType, LocateExpression)
def contact_other_info(soi) :
LocateType, LocateExpression = self.address_book_page_itmes['addcontacts_page.contactpersoncomment'].split(">")
imprimer le type de localisation, localiser l'expression
retourner getElement (self.driver, LocateType, LocateExpression)
def contact_save_button(soi) :
LocateType, LocateExpression = self.address_book_page_itmes['addcontacts_page.savecontaceperson'].split(">")
imprimer le type de localisation, localiser l'expression
retourner getElement (self.driver, LocateType, LocateExpression)
si __name__=="__main__":
driver = webdriver.Firefox(executable_path='c:\\geckodriver')
driver.get("http://mail.126.com")
connexion (pilote, "xiaxiaoxu1987", "gloryroad")
carnet d'adresses = Carnet d'adresses (pilote)
temps.sommeil(5)
carnet d'adresses.address_book_link().click()
carnet d'adresses.add_contact_button().click()
carnet d'adresses.contact_name().send_keys("sam")
carnet d'adresses.contact_email().send_keys("[email protected]")
carnet d'adresses.contact_is_star().click()
carnet d'adresses.contact_mobile().send_keys("18142244444")
carnet d'adresses.contact_other_info().send_keys("moi-même")
carnet d'adresses.contact_save_button().click()
Résultat : OK
C:\Python27\python.exe D:/test/dataDrivenTestPractice1/PageObject/AddressBook.py
self.login_page_items : {'login_page.loginbutton' : 'id>dologin', 'login_page.username' : "xpath>//input[@name='email']", 'login_page.frame' : 'id>x- URS-iframe', 'login_page.password' : "xpath>//input[@name='password']"}
self.address_book_page : {'home_page.addressbook' : "xpath>//div[text()='\xe9\x80\x9a\xe8\xae\xaf\xe5\xbd\x95']"}
self.address_book_page_itmes : {'addcontacts_page.createcontactsbtn' : "xpath>//span[text()='\xe6\x96\xb0\xe5\xbb\xba\xe8\x81\x94\xe7\xb3\xbb\xe4\ xba\xba']", 'addcontacts_page.contactpersonmobile' : "xpath>//*[@id='iaddress_TEL_wrap']//dd//input", 'addcontacts_page.contactpersonemail' : "xpath>//*[@id ='iaddress_MAIL_wrap']//input", 'addcontacts_page.contactpersoncomment' : 'xpath>//textarea', 'addcontacts_page.contactpersonname' : "xpath>//a[@title='\xe7\xbc\x96\xe8\ xbe\x91\xe8\xaf\xa6\xe7\xbb\x86\xe5\xa7\x93\xe5\x90\x8d']/preceding-sibling::div/input", 'addcontacts_page.savecontaceperson': "xpath>/ /span[.='\xe7\xa1\xae \xe5\xae\x9a']", 'addcontacts_page.starcontacts' :"xpath>//span[text()='\xe8\xae\xbe\xe4\xb8\xba\xe6\x98\x9f\xe6\xa0\x87\xe8\x81\x94\xe7\xb3\xbb\xe4 \xba\xba']/preceding-sibling::span/b"}
xpath //div[text()='Carnet d'adresses']
xpath //span[text()='Nouveau contact']
xpath //a[@title='Modifier le nom détaillé']/preceding-sibling::div/input
xpath //*[@id='iaddress_MAIL_wrap']//input
xpath //span[text()='Définir comme contact étoile']/preceding-sibling::span/b
xpath //*[@id='iaddress_TEL_wrap']//dd//input
XPath //zone de texte
xpath //span[.='OK']
Maintenant, nous avons encapsulé l'opération d'ajout de chaque élément de la page de contact et l'avons appelé dans le code de test. Tout comme l'encapsulation de la fonction de connexion, nous avons encapsulé l'opération d'ajout de chaque élément de la page de contact dans un autre fichier. , appelez-le simplement directement dans le programme principal, ce qui est pratique à utiliser.
Étape 10 : encapsulez séparément la fonction d'ajout de contact du carnet d'adresses
Créez un nouveau fichier add_contact.py sous le package Action
add_contact.py :
#encodage=utf-8
#auteur-Xia Xiaoxu
à partir de l'importation PageObject.AddressBook *
à partir du pilote Web d'importation de sélénium
def add_contact (pilote):
driver.switch_to.default_content()
carnet d'adresses = Carnet d'adresses (pilote)
carnet d'adresses.address_book_link().click()
carnet d'adresses.add_contact_button().click()
carnet d'adresses.contact_name().send_keys("sam")
carnet d'adresses.contact_email().send_keys("[email protected]")
carnet d'adresses.contact_is_star().click()
carnet d'adresses.contact_mobile().send_keys("18142244444")
carnet d'adresses.contact_other_info().send_keys("moi-même")
carnet d'adresses.contact_save_button().click()
si __name__=='__main__' :
driver=webdriver.Firefox(executable_path="c:\\geckodriver")
driver.get("http://mail.126.com")
connexion (pilote, "xiaxiaoxu1987", "gloryroad")
add_contact (pilote)
résultat:
C:\Python27\python.exe D:/test/dataDrivenTestPractice1/Action/add_contact.py
self.login_page_items : {'login_page.loginbutton' : 'id>dologin', 'login_page.username' : "xpath>//input[@name='email']", 'login_page.frame' : 'id>x- URS-iframe', 'login_page.password' : "xpath>//input[@name='password']"}
Processus terminé avec le code de sortie 0
Encapsuler davantage, remplacer la partie d'entrée par des paramètres
#encodage=utf-8
#auteur-Xia Xiaoxu
à partir de l'importation PageObject.AddressBook *
à partir du pilote Web d'importation de sélénium
def add_contact(driver,name="",email="",is_star=True,mobile="",otherinfo="") :
driver.switch_to.default_content()
carnet d'adresses = Carnet d'adresses (pilote)
carnet d'adresses.address_book_link().click()
carnet d'adresses.add_contact_button().click()
carnet d'adresses.contact_name().send_keys(nom)
carnet d'adresses.contact_email().send_keys(email)
si is_star==Vrai :
carnet d'adresses.contact_is_star().click()
carnet d'adresses.contact_mobile().send_keys(mobile)
carnet d'adresses.contact_other_info().send_keys(autresinformations)
carnet d'adresses.contact_save_button().click()
si __name__=='__main__' :
driver=webdriver.Firefox(executable_path="c:\\geckodriver")
driver.get("http://mail.126.com")
connexion (pilote, "xiaxiaoxu1987", "gloryroad")
add_contact(driver,"xiaxiaoxu","[email protected]",True,"13333334444","gloryroad")
pilote.quit()
Résultat : OK
C:\Python27\python.exe D:/test/dataDrivenTestPractice1/Action/add_contact.py
self.login_page_items : {'login_page.loginbutton' : 'id>dologin', 'login_page.username' : "xpath>//input[@name='email']", 'login_page.frame' : 'id>x- URS-iframe', 'login_page.password' : "xpath>//input[@name='password']"}
Processus terminé avec le code de sortie 0
À ce stade, nous avons encapsulé la plupart des fonctions. Essayons maintenant d'appeler ces fonctions dans le programme principal :
TestScript.py :
#encodage=utf-8
#auteur-Xia Xiaoxu
à partir du pilote Web d'importation de sélénium
heure d'importation
à partir de selenium.webdriver.support.ui importer WebDriverWait
à partir de selenium.webdriver.common.by import Par
à partir de selenium.common.exceptions importer TimeoutException, NoSuchElementException
traçage des importations
à partir de l'importation PageObject.Login_Page *
à partir de l'importation PageObject.AddressBook *
depuis l'importation Action.add_contact *
à partir de l'importation Action.login *
driver=webdriver.Firefox(executable_path='c:\\geckodriver')
driver.get('http://mail.126.com')
connexion (pilote, "xiaxiaoxu1987", "gloryroad")
add_contact(driver,"xiaxiaoxu","[email protected]",True,"13333334444","gloryroad")
pilote.quit()
Résultat : ça marche bien.
C:\Python27\python.exe D:/test/dataDrivenTestPractice1/TestScript/TestScript.py
Processus terminé avec le code de sortie 0
À en juger par les appels dans le programme principal, certaines données doivent encore être saisies manuellement, telles que les noms d'utilisateur, les mots de passe et les informations de contact qui doivent être ajoutées. Si vous devez ajouter plusieurs contacts, vous devez les saisir. plusieurs fois. Étape suivante Voyons comment séparer cette partie des données du programme et l'enregistrer dans un fichier. Cette fois, nous la mettrons dans Excel, puis utiliserons la méthode d'exploitation d'Excel pour extraire les données.
Étape 11-Encapsuler les opérations Excel
Créez un fichier Excel et mettez les informations du compte 126 dans la première feuille.
La deuxième feuille contient les contacts :
Créez un nouveau package TestData sous le projet et placez le fichier Excel sous le package.
Excel.py :
#encodage=utf-8
#auteur-Xia Xiaoxu
# encodage=utf-8
depuis openpyxl importer load_workbook
à partir d'openpyxl.styles, importez la bordure, le côté, la police
heure d'importation
à partir de l'importation ProjectVar.var *
classe parseExcel (objet):
def __init__(soi, excelPath) :
self.excelPath = excelPath
self.workbook = load_workbook(excelPath) # pour Excel
self.sheet = self.workbook.active # Récupère la première feuille
self.font = Police (couleur = Aucun)
self.colorDict = {"rouge": 'FFFF3030', "vert": 'FF008B00'}
#Définissez l'objet de feuille actuellement à utiliser et utilisez l'index pour obtenir la feuille correspondante
def set_sheet_by_index(self, sheet_index):
nom_feuille = self.workbook.get_sheet_names()[sheet_index]
self.sheet = self.workbook.get_sheet_by_name(sheet_name)
retourner self.sheet
# Récupère le nom de la feuille par défaut actuelle
def get_default_sheet(soi) :
retourner self.sheet.title
#Définissez l'objet de feuille actuellement à utiliser et utilisez le nom de la feuille pour obtenir la feuille correspondante
def set_sheet_by_name(self, sheet_name) :
feuille = self.workbook.get_sheet_by_name(sheet_name)
self.sheet = feuille
retourner self.sheet
# Obtenez le nombre maximum de lignes dans la feuille par défaut
def get_max_row_no(self):
retourner self.sheet.max_row
# Obtenez le nombre maximum de colonnes de la feuille par défaut
def get_max_col_no(self):
retourner self.sheet.max_column
# Obtenez le numéro de ligne minimum (de départ) de la feuille par défaut
def get_min_row_no(self):
retourner self.sheet.min_row
# Obtenez le numéro de colonne minimum (de départ) de la feuille par défaut
def get_min_col_no(self):
retourner self.sheet.min_column
# Récupère tous les objets lignes de la feuille par défaut,
def get_all_rows(self):
liste de retour (self.sheet.iter_rows())
# la liste de retour (self.rows) peut également être utilisée
# Récupère tous les objets de colonne dans la feuille par défaut
def get_all_cols(self):
liste de retour (self.sheet.iter_cols())
# la liste de retour (self.sheet.columns) peut également être utilisée
# Récupère une colonne de la feuille par défaut, la première colonne commence à 0
def get_single_col(self, col_no) :
retourner self.get_all_cols()[col_no]
# Récupère une certaine ligne de la feuille par défaut, la première ligne commence à 0
def get_single_row(self, row_no) :
retourner self.get_all_rows()[row_no]
# À partir de la feuille par défaut, obtenez la cellule spécifiée via le numéro de ligne et le numéro de colonne. Notez que le numéro de ligne et le numéro de colonne commencent à 1
def get_cell(self, row_no, col_no) :
retourner self.sheet.cell(row=row_no, column=col_no)
# À partir de la feuille par défaut, obtenez le contenu de la cellule spécifiée via le numéro de ligne et le numéro de colonne. Notez que le numéro de ligne et le numéro de colonne commencent à 1
def get_cell_content(self, row_no, col_no) :
retourner self.sheet.cell(row=row_no, column=col_no).value
# À partir de la feuille par défaut, écrivez le contenu spécifié dans la cellule spécifiée via le numéro de ligne et le numéro de colonne. Notez que le numéro de ligne et le numéro de colonne commencent à 1
# Lors de l'appel de cette méthode, Excel ne doit pas être ouvert.
def write_cell_content(self, row_no, col_no, content, font=None) :
self.sheet.cell(row=row_no, column=col_no).value = contenu
self.workbook.save(self.excelPath)
retourner self.sheet.cell(row=row_no, column=col_no).value
# À partir de la feuille par défaut, écrivez la date actuelle dans la cellule spécifiée via le numéro de ligne et le numéro de colonne. Notez que le numéro de ligne et le numéro de colonne commencent à 1
# Lors de l'appel de cette méthode, Excel ne doit pas être ouvert.
def write_cell_current_time(self, row_no, col_no) :
heure1 = heure.strftime("%Y-%m-%d %H:%M:%S")
self.sheet.cell(row=row_no, column=col_no).value = str(time1)
self.workbook.save(self.excelPath)
retourner self.sheet.cell(row=row_no, column=col_no).value
def save_excel_file(self):
self.workbook.save(self.excelPath)
si __name__ == '__main__' :
#Tester le code
p = parseExcel (test_data_excel_path)
print u"Obtenir la feuille par défaut :", p.get_default_sheet()
print u"Définir l'index de la feuille sur 1", p.set_sheet_by_index(1)
print u"Obtenir la feuille par défaut :", p.get_default_sheet()
print u"Définir l'index de la feuille à 0", p.set_sheet_by_index(0)
print u"Obtenir la feuille par défaut :", p.get_default_sheet()
print u"Nombre maximum de lignes :", p.get_max_row_no()
print u"Nombre maximum de colonnes :", p.get_max_col_no()
print u"Numéro minimum de ligne de départ :", p.get_min_row_no()
print u"Nombre minimum de colonnes de départ :", p.get_min_col_no()
print u"Tous les objets de ligne :", p.get_all_rows()
print u"Tous les objets de colonne :", p.get_all_cols()
print u"Obtenir une certaine colonne (2) :", p.get_single_col(2)
print u"Obtenir une certaine ligne(1) :", p.get_single_row(1)
print u"Obtenir le numéro de ligne et le numéro de colonne (2,2) cellule :", p.get_cell(2, 2)
print u"Obtenir le contenu de la cellule du numéro de ligne et du numéro de colonne (2, 2)", p.get_cell_content(2, 2)
print u"le numéro de ligne et de colonne écrit le contenu (11,11) : 'xiaxiaoxu'", p.write_cell_content(11, 11, 'xiaxiaoxu') #
print u"Le numéro de ligne et le numéro de colonne sont écrits dans la date actuelle (13,13) :", p.write_cell_current_time(13, 13)
Résultat : OK
C:\Python27\python.exe D:/test/dataDrivenTestPractice1/Util/Excel.py
Récupérer la fiche par défaut : Contact
Définir l'index de la feuille sur 1 <Worksheet "\u8054\u7cfb\u4eba">
Récupérer la fiche par défaut : Contact
Définir l'index de la feuille sur 0 <Feuille de travail "126\u8d26\u53f7">
Obtenez la feuille par défaut : 126 comptes
Nombre maximum de lignes : 3
Nombre maximum de colonnes : 6
Nombre minimum de lignes de départ : 1
Nombre minimum de colonnes de départ : 1
所有行对象: [(<Cellule u'126\u8d26\u53f7'.A1>, <Cellule u'126\u8d26\u53f7'.B1>, <Cellule u'126\u8d26\u53f7'.C1>, <Cellule u'126\u8d26\u53f7'.D1>, <Cellule u'126\u8d26\u53f7'.E1>, <Cellule u'126\u8d26\u53f7'.F1>), (<Cellule u'126\u8d26\ u53f7'.A2>, <Cellule u'126\u8d26\u53f7'.B2>, <Cellule u'126\u8d26\u53f7'.C2>, <Cellule u'126\u8d26\u53f7'.D2>, <Cellule u'126\u8d26\u53f7'.E2>, <Cellule u'126\u8d26\u53f7'.F2>), (<Cellule u'126\u8d26\u53f7'.A3>, <Cellule u'126\u8d26\ u53f7'.B3>, <Cellule u'126\u8d26\u53f7'.C3>, <Cellule u'126\u8d26\u53f7'.D3>, <Cellule u'126\u8d26\u53f7'.E3>, <Cellule u'126\u8d26\u53f7'.F3>)]
所有列对象: [(<Cellule u'126\u8d26\u53f7'.A1>, <Cellule u'126\u8d26\u53f7'.A2>, <Cellule u'126\u8d26\u53f7'.A3>), ( <Cellule u'126\u8d26\u53f7'.B1>, <Cellule u'126\u8d26\u53f7'.B2>, <Cellule u'126\u8d26\u53f7'.B3>), (<Cellule u'126\ u8d26\u53f7'.C1>, <Cellule u'126\u8d26\u53f7'.C2>, <Cellule u'126\u8d26\u53f7'.C3>), (<Cellule u'126\u8d26\u53f7'.D1 >, <Cellule u'126\u8d26\u53f7'.D2>, <Cellule u'126\u8d26\u53f7'.D3>), (<Cellule u'126\u8d26\u53f7'.E1>, <Cellule u' 126\u8d26\u53f7'.E2>, <Cellule u'126\u8d26\u53f7'.E3>), (<Cellule u'126\u8d26\u53f7'.F1>, <Cellule u'126\u8d26\u53f7' .F2>, <Cellule u'126\u8d26\u53f7'.F3>)]
Obtenez une certaine colonne (2) : (<Cell u'126\u8d26\u53f7'.C1>, <Cell u'126\u8d26\u53f7'.C2>, <Cell u'126\u8d26\u53f7'.C3> )
获取某一行(1): (<Cellule u'126\u8d26\u53f7'.A2>, <Cellule u'126\u8d26\u53f7'.B2>, <Cellule u'126\u8d26\u53f7'.C2>, <Cellule u'126\u8d26\u53f7'.D2>, <Cellule u'126\u8d26\u53f7'.E2>, <Cellule u'126\u8d26\u53f7'.F2>)
Obtenez le numéro de ligne et le numéro de colonne (2,2) de la cellule : <Cell u'126\u8d26\u53f7'.B2>
Obtenez le contenu des cellules du numéro de ligne et du numéro de colonne (2,2) xiaxiaoxu1987
Le numéro de ligne et le numéro de colonne écrivent le contenu (11,11) : 'xiaxiaoxu' xiaxiaoxu
Le numéro de ligne et le numéro de colonne sont écrits dans la date actuelle (13,13) : 2018-07-10 21:28:14
Processus terminé avec le code de sortie 0
À ce stade, l’opération Excel a été encapsulée. Essayons de lire les données dans le programme principal.
TestScript.py :
#encodage=utf-8
#auteur-Xia Xiaoxu
à partir du pilote Web d'importation de sélénium
heure d'importation
à partir de selenium.webdriver.support.ui importer WebDriverWait
à partir de selenium.webdriver.common.by import Par
à partir de selenium.common.exceptions importer TimeoutException, NoSuchElementException
traçage des importations
à partir de l'importation PageObject.Login_Page *
à partir de l'importation PageObject.AddressBook *
depuis l'importation Action.add_contact *
à partir de l'importation Action.login *
à partir de l'importation ProjectVar.var *
à partir de l'importation Util.Excel *
driver=webdriver.Firefox(executable_path='c:\\geckodriver')
driver.get('http://mail.126.com')
pe=parseExcel(test_data_excel_path)
pe.set_sheet_by_name(u"Compte 126")
imprimer pe.get_default_sheet()
lignes=pe.get_all_rows()[1:]
pour l'identifiant, ligne dans enumerate (lignes):
si ligne[4].value =='y' :
nom d'utilisateur = ligne[1].value
mot de passe = ligne[2].value
imprimer le nom d'utilisateur, le mot de passe
essayer:
login (pilote, nom d'utilisateur, mot de passe)
pe.set_sheet_by_name(u"Contact")
imprimer pe.get_default_sheet()
rows1=pe.get_all_rows()[1:]
imprimer "lignes1 :", lignes1
pour id1,ligne dans enumerate(rows1):
si row[7].value == 'y' :
essayer:
#print row[1].value,row[2].value,row[3].value,row[4].value,row[5].value
#print "exécuter1"
add_contact (pilote, ligne [1]. valeur, ligne [2]. valeur, ligne [3]. valeur, ligne [4]. valeur, ligne [5]. valeur)
imprimer "assert word:",row[6].value dans driver.page_source
imprimer la ligne[6].value
pe.write_cell_content(id1+2,10,"pass")
sauf exception,e :
imprimer u "Message d'exception :", e.message
pe.write_cell_content(id1+2,10,"échec")
autre:
pe.write_cell_content(id1+2,10,u"忽略")
continuer
sauf exception,e :
pe.set_sheet_by_name(u"Compte 126")
imprimer u"Message d'exception :",e
pe.write_cell_content(id+2,5,"échec")
autre:
pe.set_sheet_by_name(u"Compte 126")
pe.write_cell_content(id+2,6,u"忽略")
continuer
Résultat : exécution ok
C:\Python27\python.exe D:/test/dataDrivenTestPractice1/TestScript/TestScript.py
126compte
xiaxiaoxu1987 route de la gloire
Personne de contact
lignes 1 : [(<Cellule u'\u8054\u7cfb\u4eba'.A2>, <Cellule u'\u8054\u7cfb\u4eba'.B2>, <Cellule u'\u8054\u7cfb\u4eba'.C2>, < Cellule u'\u8054\u7cfb\u4eba'.D2>, <Cellule u'\u8054\u7cfb\u4eba'.E2>, <Cellule u'\u8054\u7cfb\u4eba'.F2>, <Cellule u'\u8054 \u7cfb\u4eba'.G2>, <Cellule u'\u8054\u7cfb\u4eba'.H2>, <Cellule u'\u8054\u7cfb\u4eba'.I2>, <Cellule u'\u8054\u7cfb\u4eba' .J2>), (<Cellule u'\u8054\u7cfb\u4eba'.A3>, <Cellule u'\u8054\u7cfb\u4eba'.B3>, <Cellule u'\u8054\u7cfb\u4eba'.C3> , <Cellule u'\u8054\u7cfb\u4eba'.D3>, <Cellule u'\u8054\u7cfb\u4eba'.E3>, <Cellule u'\u8054\u7cfb\u4eba'.F3>, <Cellule u' \u8054\u7cfb\u4eba'.G3>, <Cellule u'\u8054\u7cfb\u4eba'.H3>,<Cellule u'\u8054\u7cfb\u4eba'.I3>, <Cellule u'\u8054\u7cfb\u4eba'.J3>), (<Cellule u'\u8054\u7cfb\u4eba'.A4>, <Cellule u'\u8054\u7cfb\u4eba'.A4> '\u8054\u7cfb\u4eba'.B4>, <Cellule u'\u8054\u7cfb\u4eba'.C4>, <Cellule u'\u8054\u7cfb\u4eba'.D4>, <Cellule u'\u8054\u7cfb \u4eba'.E4>, <Cellule u'\u8054\u7cfb\u4eba'.F4>, <Cellule u'\u8054\u7cfb\u4eba'.G4>, <Cellule u'\u8054\u7cfb\u4eba'.H4 >, <Cellule u'\u8054\u7cfb\u4eba'.I4>, <Cellule u'\u8054\u7cfb\u4eba'.J4>, (<Cellule u'\u8054\u7cfb\u4eba'.A5>, < Cellule u'\u8054\u7cfb\u4eba'.B5>, <Cellule u'\u8054\u7cfb\u4eba'.C5>, <Cellule u'\u8054\u7cfb\u4eba'.D5>, <Cellule u'\u8054 \u7cfb\u4eba'.E5>, <Cellule u'\u8054\u7cfb\u4eba'.F5>,<Cellule u'\u8054\u7cfb\u4eba'.G5>, <Cellule u'\u8054\u7cfb\u4eba'.H5>, <Cellule u'\u8054\u7cfb\u4eba'.I5>, <Cellule u'\ u8054\u7cfb\u4eba'.J5>)]
affirmer le mot : vrai
affirmer le mot : vrai
John Doe
Processus terminé avec le code de sortie 0
Résultats Excel :
À ce stade, la plupart des fonctions du framework ont été encapsulées. Ensuite, construisons le module de journalisation afin que le programme puisse imprimer des journaux lors de son exécution.
Étape 12 : Ajouter le module de journal
Créez un nouveau fichier de configuration du journal Logger.conf sous le package Conf, qui configure l'enregistreur, le processeur et le formateur. Les détails spécifiques du journal seront répertoriés plus tard.
#logger.conf
############################################# #
[loggers]
keys=root,example01,example02
[logger_root]
level=DEBUG
handlers=hand01,hand02
[logger_example01]
handlers=hand01,hand02
qualname=example01
propagate=0
[logger_example02]
handlers=hand01,hand03
qualname=example02
propagate=0
###############################################
[gestionnaires]
clés = hand01, hand02, hand03
[handler_hand01]
class =
niveau StreamHandler = INFO
formatter = form01
args = (sys.stderr,)
[handler_hand02]
classe =
niveau FileHandler = DEBUG
formatter=form01
args=('DataDrivenFrameWork.log', 'a')
[handler_hand03]
class=handlers.RotatingFileHandler
level=INFO
formatter=form01
args=('DataDrivenFrameWork.log', 'a', 10*1024*1024, 5 )
###############################################
[formatteurs ]
clés=form01,form02
[formatter_form01]
format=%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s datefmt=%Y-%m-%
d %H:%M:%S
[formatter_form02]
format=%(name)-12s : %(levelname)-8s %(message)s
datefmt=%Y-%m-%d %H:%M:%S
Créez un nouveau fichier log.py sous le package Util pour encapsuler l'opération de journalisation
Log.py :
#encodage=utf-8
#auteur-Xia Xiaoxu
journalisation des importations
importer le fichier logging.config
à partir de l'importation ProjectVar.var *
#Lire le fichier de configuration du journal
logging.config.fileConfig(chemin_projet+"\\Conf\\Logger.conf")
#Sélectionnez un format de journal
logger=logging.getLogger("exemple02")
erreur def (message) :
#Imprimer les informations sur le niveau de débogage
enregistreur.erreur (message)
informations de définition (message) :
#Imprimer les informations au niveau des informations
logger.info (message)
avertissement def (message) :
#Imprimer les informations sur le niveau d'avertissement
enregistreur.avertissement (message)
si __name__=="__main__":
#Tester le code
info("salut")
print "chemin du fichier de configuration :", chemin_projet+"\\Conf\\Logger.conf"
erreur("monde!")
avertissement("gloryroad!")
Résultat : OK
C:\Python27\python.exe D:/test/dataDrivenTestPractice1/Util/log.py
2018-07-11 21:32:12 log.py[line:19] INFO salut
chemin du fichier de configuration : D:\test\dataDrivenTestPractice1\Conf\Logger.conf
2018-07-11 21:32:12 log.py[line:15] ERREUR monde !
2018-07-11 21:32:12 log.py[line:23] AVERTISSEMENT Gloryroad !
Processus terminé avec le code de sortie 0
L’encapsulation du log est maintenant ok. Modifions le programme principal et appelons le log.
TestScript.py :
#encodage=utf-8
#auteur-Xia Xiaoxu
à partir du pilote Web d'importation de sélénium
heure d'importation
à partir de selenium.webdriver.support.ui importer WebDriverWait
à partir de selenium.webdriver.common.by import Par
à partir de selenium.common.exceptions importer TimeoutException, NoSuchElementException
traçage des importations
à partir de l'importation PageObject.Login_Page *
à partir de l'importation PageObject.AddressBook *
depuis l'importation Action.add_contact *
à partir de l'importation Action.login *
à partir de l'importation ProjectVar.var *
à partir de l'importation Util.Excel *
à partir de l'importation Util.log *
driver=webdriver.Firefox(executable_path='c:\\geckodriver')
driver.get('http://mail.126.com')
pe=parseExcel(test_data_excel_path)
pe.set_sheet_by_name(u"Compte 126")
imprimer pe.get_default_sheet()
lignes=pe.get_all_rows()[1:]
pour l'identifiant, ligne dans enumerate (lignes):
si ligne[4].value =='y' :
nom d'utilisateur = ligne[1].value
mot de passe = ligne[2].value
imprimer le nom d'utilisateur, le mot de passe
essayer:
login (pilote, nom d'utilisateur, mot de passe)
pe.set_sheet_by_name(u"Contact")
imprimer pe.get_default_sheet()
rows1=pe.get_all_rows()[1:]
imprimer "lignes1 :", lignes1
test_data_pass_flag=Représentation True#Result, utilisée pour l'écriture finale des résultats Excel
pour id1,ligne dans enumerate(rows1):
si row[7].value == 'y' :
essayer:
#print row[1].value,row[2].value,row[3].value,row[4].value,row[5].value
imprimer "log0711", ligne [1], ligne [1].value
imprimer "log0711", type (ligne [1]. valeur)
#Effectuer l'opération réelle d'ajout de contacts
add_contact (pilote, ligne [1]. valeur, ligne [2]. valeur, ligne [3]. valeur, ligne [4]. valeur, ligne [5]. valeur)
print "assert word:",row[6].value
affirmer la ligne [6] .value dans driver.page_source
pe.write_cell_content(id1+2,10,"pass")#assert ne signale pas d'erreur, indiquant que l'assertion est réussie
sauf exception,e :
#print u"Message d'exception 01",e.message
pe.write_cell_content(id1+2,10,"échec")
test_data_pass_flag=False#Le code atteint ce point, indiquant qu'il y a une exception et que le test a échoué.
info(u"Message d'exception 01" + e.message) #Journal de sortie
else:#L'identifiant de la description est 'n', ignorez les données
pe.write_cell_content(id1+2,10,u"忽略")
continuer
if test_data_pass_flag ==True:#Si le flag est True, le résultat est réussi
pe.set_sheet_by_name(u"Compte 126")
pe.write_cell_content(id+2,5,"成功")
else:#Indique que l'indicateur est False
pe.set_sheet_by_name(u"Compte 126")
pe.write_cell_content(id+2,5,"Échec")
sauf exception,e :
pe.set_sheet_by_name(u"Compte 126")
#print u"Message d'exception 02:",e
pe.write_cell_content(id+2,6,"échec")
info(u"Message d'exception 02 :"+e.message)#Journal de sortie
temps.sommeil(2)
pilote.quit()
else:#Prendre cette branche, indiquant que l'identifiant est "n"
pe.set_sheet_by_name(u"Compte 126")
pe.write_cell_content(id+2,6,u"忽略")
continuer
Résultat : Exécuter OK
C:\Python27\python.exe D:/test/dataDrivenTestPractice1/TestScript/TestScript.py
126compte
xiaxiaoxu1987 route de la gloire
2018-07-11 22:55:25 log.py[line:19] INFO connexion réussie
Personne de contact
lignes 1 : [(<Cellule u'\u8054\u7cfb\u4eba'.A2>, <Cellule u'\u8054\u7cfb\u4eba'.B2>, <Cellule u'\u8054\u7cfb\u4eba'.C2>, < Cellule u'\u8054\u7cfb\u4eba'.D2>, <Cellule u'\u8054\u7cfb\u4eba'.E2>, <Cellule u'\u8054\u7cfb\u4eba'.F2>, <Cellule u'\u8054 \u7cfb\u4eba'.G2>, <Cellule u'\u8054\u7cfb\u4eba'.H2>, <Cellule u'\u8054\u7cfb\u4eba'.I2>, <Cellule u'\u8054\u7cfb\u4eba' .J2>), (<Cellule u'\u8054\u7cfb\u4eba'.A3>, <Cellule u'\u8054\u7cfb\u4eba'.B3>, <Cellule u'\u8054\u7cfb\u4eba'.C3> , <Cellule u'\u8054\u7cfb\u4eba'.D3>, <Cellule u'\u8054\u7cfb\u4eba'.E3>, <Cellule u'\u8054\u7cfb\u4eba'.F3>, <Cellule u' \u8054\u7cfb\u4eba'.G3>, <Cellule u'\u8054\u7cfb\u4eba'.H3>,<Cellule u'\u8054\u7cfb\u4eba'.I3>, <Cellule u'\u8054\u7cfb\u4eba'.J3>), (<Cellule u'\u8054\u7cfb\u4eba'.A4>, <Cellule u'\u8054\u7cfb\u4eba'.A4> '\u8054\u7cfb\u4eba'.B4>, <Cellule u'\u8054\u7cfb\u4eba'.C4>, <Cellule u'\u8054\u7cfb\u4eba'.D4>, <Cellule u'\u8054\u7cfb \u4eba'.E4>, <Cellule u'\u8054\u7cfb\u4eba'.F4>, <Cellule u'\u8054\u7cfb\u4eba'.G4>, <Cellule u'\u8054\u7cfb\u4eba'.H4 >, <Cellule u'\u8054\u7cfb\u4eba'.I4>, <Cellule u'\u8054\u7cfb\u4eba'.J4>, (<Cellule u'\u8054\u7cfb\u4eba'.A5>, < Cellule u'\u8054\u7cfb\u4eba'.B5>, <Cellule u'\u8054\u7cfb\u4eba'.C5>, <Cellule u'\u8054\u7cfb\u4eba'.D5>, <Cellule u'\u8054 \u7cfb\u4eba'.E5>, <Cellule u'\u8054\u7cfb\u4eba'.F5>,<Cellule u'\u8054\u7cfb\u4eba'.G5>, <Cellule u'\u8054\u7cfb\u4eba'.H5>, <Cellule u'\u8054\u7cfb\u4eba'.I5>, <Cellule u'\ u8054\u7cfb\u4eba'.J5>)]
log0711 <Cell u'\u8054\u7cfb\u4eba'.B2> lily
log0711 <type 'unicode'>
assert word: [email protected]
Process finished with exit code 0
login.py文件里也可以在执行登录动作后打个日志,提示登录成功。
至此,主程序中实现了读取数据、登录邮箱、添加联系人、往excel里写入测试结果,基本的功能已经搞定了,下面再搞一个地方,就接近完美了,就是对时间的封装,在程序中调用时间函数写入指定的时间格式。
步骤13—常用时间操作的封装
在Util包下新建FormatTime.py
FormatTime.py
#encoding=utf-8
#author-夏晓旭
#encoding=utf-8
import time
from datetime import timedelta,date
def date_time_chinese():
print u"returns the current time string,format for YYYY年mm月dd日HH时MM分SS秒"
return time.strftime("%Y年%m月%d日 %H时%M分%S秒",time.localtime())
def date_chinese():
print u"returns the current time string, format for YYYY年mm月dd日"
return time.strftime("%Y年%m月%d日",time.localtime())
def time_chinese():
print u"returns the current time string,format for HH时 MM分 SS秒"
return time.strftime("%H heure %M minute %S seconde", time.localtime())
def date_time() :
print "renvoie la chaîne d'heure actuelle, au format AAAA-mm-jj HH:MM:SS"
return time.strftime("%Y-%m-%d %H:%M:%S",time.localtime())
def date_time_slash() :
print "renvoie la chaîne d'heure actuelle, au format AAAA/mm/jj HH:MM:SS"
return time.strftime("%Y/%m/%d %H:%M:%S",time.localtime())
dates par défaut() :
print "renvoie la chaîne d'heure actuelle, au format AAAA-mm-jj"
return time.strftime("%Y-%m-%d",time.localtime())
def date_slash() :
print "renvoie la chaîne d'heure actuelle, au format AAAA/mm/jj"
return time.strftime("%Y/%m/%d",time.localtime())
def fois() :
print "renvoie la chaîne d'heure actuelle, au format HH:MM:SS"
return time.strftime("%H:%M:%S",time.localtime())
année par défaut() :
print "renvoie la chaîne d'heure actuelle, le format pour l'année"
retourner time.strftime("%Y",time.localtime())
mois par défaut() :
print "renvoie la chaîne d'heure actuelle, le format du mois"
retourner time.strftime("%m",time.localtime())
jour def() :
print "renvoie la chaîne d'heure actuelle, le format du jour"
return time.strftime("%d",time.localtime())
heure par défaut() :
print "renvoie la chaîne d'heure actuelle, au format Heure"
retourner time.strftime("%H",time.localtime())
def minute() :
print "renvoie la chaîne de l'heure actuelle, au format minute"
retourner time.strftime("%M",time.localtime())
def secondes() :
print "renvoie la chaîne d'heure actuelle, formate en secondes"
retourner time.strftime("%S",time.localtime())
def str_to_tuple(stime) :
print "renvoie la variable chaîne dans des tuples temporels"
return time.strptime(stime,"%Y-%m-%d %H:%M:%S")
def add_date(jour_num):
aujourd'hui=date.aujourd'hui()
print "renvoie la date actuelle-%s et un intervalle de temps-%s" %(today,day_num)
times=aujourd'hui+timedelta(days=day_num)
heures de retour
def sub_date(jour_num) :
aujourd'hui=date.aujourd'hui()
print "renvoie la date actuelle-%s moins un intervalle de temps-%s" %(today,day_num)
times=aujourd'hui-timedelta(days=day_num)
heures de retour
si __name__=='__main__' :
#Tester le code
imprimer date_time_chinese()
imprimer date_chinese()
imprimer time_chinese()
imprimer date_heure()
imprimer date_time_slash()
imprimer les dates()
imprimer date_slash()
temps d'impression()
année d'impression()
imprimer le mois()
jour d'impression()
heure d'impression()
imprimer la minute()
imprimer les secondes()
time1=time.strftime("%Y-%m-%d %H:%M:%S",time.localtime())
imprimer str_to_tuple (time1)
imprimer add_date(2)
imprimer sous_date(2)
Résultat : ok, le chinois n'a pas besoin d'être transcodé dans pycharm, mais le transcodage est nécessaire pour s'exécuter dans le bloc-notes.
C:\Python27\python.exe D:/test/dataDrivenTestPractice1/Util/FormatTime.py
renvoie la chaîne d'heure actuelle, au format AAAA année mm mois jj jour HH heure MM minute SS seconde
11 juillet 2018 23:01:36
renvoie la chaîne de l'heure actuelle, au format AAAA mm mois jj jour
11 juillet 2018
renvoie la chaîne d'heure actuelle, au format HH heures MM minutes SS secondes
23:01:36
renvoie la chaîne de l'heure actuelle, au format AAAA-mm-jj HH:MM:SS
2018-07-11 23:01:36
renvoie la chaîne de l'heure actuelle, au format AAAA/mm/jj HH:MM:SS
2018/07/11 23:01:36
renvoie la chaîne de l'heure actuelle, au format AAAA-mm-jj
2018-07-11
renvoie la chaîne de l'heure actuelle, au format AAAA/mm/jj
2018/07/11
renvoie la chaîne de l'heure actuelle, au format HH:MM:SS
23:01:36
renvoie la chaîne d'heure actuelle, le format de l'année
2018
renvoie la chaîne d'heure actuelle, le format du mois
07
renvoie la chaîne de l'heure actuelle, le format du jour
11
renvoie la chaîne d'heure actuelle, au format Heure
23
renvoie la chaîne de l'heure actuelle, au format minute
01
renvoie la chaîne de l'heure actuelle, formate en secondes
36
renvoie la variable chaîne dans des tuples temporels
time.struct_time(tm_year=2018, tm_mon=7, tm_mday=11, tm_hour=23, tm_min=1, tm_sec=36, tm_wday=2, tm_yday=192, tm_isdst=-1)
renvoie la date actuelle-2018-07-11 et un intervalle de temps-2
2018-07-13
renvoie la date actuelle-2018-07-11 moins un intervalle de temps-2
2018-07-09
Processus terminé avec le code de sortie 0
Modifiez le programme principal, appelez la fonction heure et imprimez l'heure
TestScript.py :
#encodage=utf-8
#auteur-Xia Xiaoxu
à partir du pilote Web d'importation de sélénium
heure d'importation
à partir de selenium.webdriver.support.ui importer WebDriverWait
à partir de selenium.webdriver.common.by import Par
à partir de selenium.common.exceptions importer TimeoutException, NoSuchElementException
traçage des importations
à partir de l'importation PageObject.Login_Page *
à partir de l'importation PageObject.AddressBook *
depuis l'importation Action.add_contact *
à partir de l'importation Action.login *
à partir de l'importation ProjectVar.var *
à partir de l'importation Util.Excel *
à partir de l'importation Util.log *
à partir de l'importation Util.FormatTime *
driver=webdriver.Firefox(executable_path='c:\\geckodriver')
driver.get('http://mail.126.com')
pe=parseExcel(test_data_excel_path)
pe.set_sheet_by_name(u"Compte 126")
imprimer pe.get_default_sheet()
lignes=pe.get_all_rows()[1:]
pour l'identifiant, ligne dans enumerate (lignes):
si ligne[4].value =='y' :
nom d'utilisateur = ligne[1].value
mot de passe = ligne[2].value
imprimer le nom d'utilisateur, le mot de passe
essayer:
login (pilote, nom d'utilisateur, mot de passe)
pe.set_sheet_by_name(u"Contact")
imprimer pe.get_default_sheet()
rows1=pe.get_all_rows()[1:]
imprimer "lignes1 :", lignes1
test_data_pass_flag=Représentation True#Result, utilisée pour l'écriture finale des résultats Excel
pour id1,ligne dans enumerate(rows1):
si row[7].value == 'y' :
essayer:
#print row[1].value,row[2].value,row[3].value,row[4].value,row[5].value
imprimer "log0711", ligne [1], ligne [1].value
imprimer "log0711", type (ligne [1]. valeur)
#Effectuer l'opération réelle d'ajout de contacts
add_contact (pilote, ligne [1]. valeur, ligne [2]. valeur, ligne [3]. valeur, ligne [4]. valeur, ligne [5]. valeur)
pe.write_cell_content(id1 + 2, 9, date_time())
print "assert word:",row[6].value
affirmer la ligne [6] .value dans driver.page_source
pe.write_cell_content(id1+2,10,"pass")#assert ne signale pas d'erreur, indiquant que l'assertion est réussie
sauf exception,e :
#print u"Message d'exception 01",e.message
pe.write_cell_content(id1+2,10,"échec")
pe.write_cell_content(id1+2,9,date_time())
test_data_pass_flag=False#Le code atteint ce point, indiquant qu'il y a une exception et que le test a échoué.
info(u"Message d'exception 01" + e.message) # Journal de sortie
else:#L'identifiant de la description est 'n', ignorez les données
pe.write_cell_content(id1+2,10,u"忽略")
pe.write_cell_content(id1 + 2, 9,date_time())
continuer
if test_data_pass_flag ==True:#Si le flag est True, le résultat est réussi
pe.set_sheet_by_name(u"Compte 126")
pe.write_cell_content(id+2,6,"成功")
else:#Indique que l'indicateur est False
pe.set_sheet_by_name(u"Compte 126")
pe.write_cell_content(id+2,6,"Échec")
sauf exception,e :
pe.set_sheet_by_name(u"Compte 126")
#print u"Message d'exception 02:",e
pe.write_cell_content(id+2,6,"échec")
info(u"Message d'exception 02 :"+e.message)#Journal de sortie
temps.sommeil(2)
pilote.quit()
else:#Prendre cette branche, indiquant que l'identifiant est "n"
pe.set_sheet_by_name(u"Compte 126")
pe.write_cell_content(id+2,6,u"忽略")
continuer
Résultat : OK
C:\Python27\python.exe D:/test/dataDrivenTestPractice1/TestScript/TestScript.py
126compte
xiaxiaoxu1987 route de la gloire
2018-07-11 23:17:39 log.py[line:19] INFO connexion réussie
Personne de contact
lignes 1 : [(<Cellule u'\u8054\u7cfb\u4eba'.A2>, <Cellule u'\u8054\u7cfb\u4eba'.B2>, <Cellule u'\u8054\u7cfb\u4eba'.C2>, < Cellule u'\u8054\u7cfb\u4eba'.D2>, <Cellule u'\u8054\u7cfb\u4eba'.E2>, <Cellule u'\u8054\u7cfb\u4eba'.F2>, <Cellule u'\u8054 \u7cfb\u4eba'.G2>, <Cellule u'\u8054\u7cfb\u4eba'.H2>, <Cellule u'\u8054\u7cfb\u4eba'.I2>, <Cellule u'\u8054\u7cfb\u4eba' .J2>), (<Cellule u'\u8054\u7cfb\u4eba'.A3>, <Cellule u'\u8054\u7cfb\u4eba'.B3>, <Cellule u'\u8054\u7cfb\u4eba'.C3> , <Cellule u'\u8054\u7cfb\u4eba'.D3>, <Cellule u'\u8054\u7cfb\u4eba'.E3>, <Cellule u'\u8054\u7cfb\u4eba'.F3>, <Cellule u' \u8054\u7cfb\u4eba'.G3>, <Cellule u'\u8054\u7cfb\u4eba'.H3>,<Cellule u'\u8054\u7cfb\u4eba'.I3>, <Cellule u'\u8054\u7cfb\u4eba'.J3>), (<Cellule u'\u8054\u7cfb\u4eba'.A4>, <Cellule u'\u8054\u7cfb\u4eba'.A4> '\u8054\u7cfb\u4eba'.B4>, <Cellule u'\u8054\u7cfb\u4eba'.C4>, <Cellule u'\u8054\u7cfb\u4eba'.D4>, <Cellule u'\u8054\u7cfb \u4eba'.E4>, <Cellule u'\u8054\u7cfb\u4eba'.F4>, <Cellule u'\u8054\u7cfb\u4eba'.G4>, <Cellule u'\u8054\u7cfb\u4eba'.H4 >, <Cellule u'\u8054\u7cfb\u4eba'.I4>, <Cellule u'\u8054\u7cfb\u4eba'.J4>, (<Cellule u'\u8054\u7cfb\u4eba'.A5>, < Cellule u'\u8054\u7cfb\u4eba'.B5>, <Cellule u'\u8054\u7cfb\u4eba'.C5>, <Cellule u'\u8054\u7cfb\u4eba'.D5>, <Cellule u'\u8054 \u7cfb\u4eba'.E5>, <Cellule u'\u8054\u7cfb\u4eba'.F5>,<Cellule u'\u8054\u7cfb\u4eba'.G5>, <Cellule u'\u8054\u7cfb\u4eba'.H5>, <Cellule u'\u8054\u7cfb\u4eba'.I5>, <Cellule u'\ u8054\u7cfb\u4eba'.J5>)]
log0711 <Cellule u'\u8054\u7cfb\u4eba'.B2> lily
log0711 <type 'unicode'>
renvoie la chaîne de l'heure actuelle, au format AAAA-mm-jj HH:MM:SS
affirmer le mot : [email protected]
renvoie la chaîne de l'heure actuelle, au format AAAA-mm-jj HH:MM:SS
renvoie la chaîne de l'heure actuelle, au format AAAA-mm-jj HH:MM:SS
renvoie la chaîne de l'heure actuelle, au format AAAA-mm-jj HH:MM:SS
Processus terminé avec le code de sortie 0
Excel écrit les résultats :
Résumer:
Maintenant, nous commençons par assembler des fonctions dispersées pour implémenter une fonction plus grande, puis organisons la fonction plus grande en une fonction plus grande. En fin de compte, ce que nous voyons dans le programme principal est la combinaison de grandes fonctions indépendantes. Voir Cela a l'air soigné, simple, très lisible et facile à entretenir.
De cette façon, nous transformons l'ensemble du cadre d'une liste dispersée de codes en encapsulant des fonctions en morceaux. Nous séparons les données et les programmes, encapsulons et intégrons une certaine fonction indépendante. Dans ce processus, nous nous familiarisons avec les étapes de construction d'un cadre. Après avoir connu les tenants et aboutissants et les avantages de l'encapsuler dans plusieurs gros blocs, lorsque vous construirez le framework de test plus tard, vous pourrez simplement suivre ces gros blocs. Il sera relativement plus facile d'accepter cette idée, cette logique et sa nécessité. comprendre pourquoi un tel cadre de test devrait être construit et les principes de ce cadre de test, puis tirer des conclusions et l'étendre à d'autres types de cadres de test.
Plus de pratique pratique ~
Voici la structure du cadre basé sur les données :
Structure du cadre basée sur les données :
Action :
fonction encapsulée des éléments opérationnels, tels que la connexion et l'ajout de contacts. . .
conf :
Fichier de configuration du journal Fichier
de configuration des éléments de positionnement Fichier
de configuration de la base de données
PageObject :
Une page est une classe, et la méthode de la classe peut obtenir des éléments associés sur la page
ProjectVar :
Chemin
du projet Variables globales liées au projet
TestData : (fichier ou Excel)
test
données de test de cas
TestScript :
Le programme principal qui exécute le framework de test : l'entrée, qui lit principalement les fichiers de données de test
et enregistre les résultats des tests.
Fonction de classe Util-Tool
:
Lire le fichier de configuration,
classe d'outils Excel , méthode
de classe temporelle pour trouver des éléments, méthode pour lire le fichier de configuration des éléments de positionnement, méthode de journalisation , modèle de rapport de capture d'écran d'opération de journalisation
Si vous avez besoin du code source du framework, vous pouvez laisser votre email dans la zone commentaire~
Enfin, je partagerai avec vous les documents et le matériel d'apprentissage que j'ai accumulés et véridiques. Si nécessaire, vous pouvez simplement les récupérer. Le contenu ci-dessus devrait être l'entrepôt de préparation le plus complet et le plus complet
pour les amis testeurs de logiciels. Afin de mieux Organisez-le Pour chaque module, j'ai également consulté de nombreux articles de blog et projets de haute qualité sur Internet, en essayant de ne manquer aucun point de connaissance. De nombreux amis se sont appuyés sur ces contenus pour les examiner et ont reçu des offres de grands fabricants tels que BATJ. a également beaucoup aidé. En tant qu'apprenant en tests de logiciels, j'espère que cela pourra également vous aider.
Suivez mon compte officiel WeChat ci-dessous pour l'obtenir gratuitement ! ↓ ↓ ↓ ↓ ↓