基於python+appium通過圖片對比來做的UI自動化


1.python + appium +圖片對比實現UI自動化:
背景:
當手機需要適配不同的語言時,測試過程中易出現因為語言不熟悉,導致UIbug被遺漏(例如setting中的描述性文字顯示不完整等等問題)
環境搭建:
需使用模塊PIL,Windows版本鏈接地址:http://pythonware.com/products/pil/
ubuntu (使用16.04虛擬機):sudo apt-get install python-imaging
安裝過程遭遇
Unable to acquire the dpkg frontend lock (/var/lib/dpkg/lock-frontend), is another process using it?
強制解鎖進行的下一步
sudo rm /var/cache/apt/archives/lock
sudo rm /var/lib/dpkg/lock
各種小毛病:
安裝PIL模塊提示python2.7沒有注冊,解決方法:
https://www.cnblogs.com/thinksasa/p/3283695.html

虛擬機連接手機提示沒有權限的問題:
在root賬號下,kill-server 然后start-server

在win7 64位會報錯:tThe _imaging C module is not installed,安裝64位的PIL可解決,
https://www.lfd.uci.edu/~gohlke/pythonlibs/#pillow
安裝后在python下執行import ImageFon,不報錯就OK。安裝過程各種不爽,用python3.6搭配64位的PIL在Windows下成功執行(上面的網址可以下載)

在使用ImageChops.difference函數時,部分結果圖片顯示為一張網格圖,導致壓根看不到兩張圖的差異,結合如下鏈接
https://blog.csdn.net/qq_41500251/article/details/82919656
對圖片進行取反,使得結果可見

邏輯梳理:
保存已確認過的UI截圖,在測試時將當前頁面進行截圖,與保存的期望截圖做對比
問題一
期望結果截圖和測試結果截圖時間不同,當前已運行的程序不同,會導致狀態欄顯示不同,並且有時候navigation bar也會不一樣(Android P手機傾斜時,出現一個轉屏操作按鈕)
方案:將圖片進行裁剪,只保留需要對比的部分。
截圖使用到如下模塊:
im = Image.open(im_path)
cropedIm = im.crop((700, 100, 1200, 1000))#此處為(左,上,右,下)坐標
cropedIm.save(r'C:\Users\Administrator\Desktop\cropped.png')
https://www.cnblogs.com/sun-haiyu/p/7127582.html
#在不同的機種上需要重新適配截圖的大小
目錄結構:
-----------
├─WlanUi.py 主程序,負責測試報告生成
│ └─Test_case 存放測試case
│ └─test_Network01.py
├─DesiredResult 此處存放期望結果圖片
│ ├─test_NetworkEN01.png
│ └─test_NetworkEN02.png
├─DiffPicture 當期望結果和世界結果不同時,生成一張差分圖,存放於此路徑
├─testReport 測試報告(.html)
├─testResult 實際測試結果截圖
├─readme.md

代碼:

 test_Network01.py

#coding=utf-8
#python3
import unittest
from appium import webdriver
import time 
import os
from PIL import Image
from PIL import ImageChops
#如下導入解決‘image file is truncated’問題
from PIL import ImageFile
ImageFile.LOAD_TRUNCATED_IMAGES = True

PATH = lambda p: os.path.abspath(p) 
def screenshot(testcase):
	path = PATH(os.getcwd() + "/TestResult") 
	if not os.path.isdir(PATH(os.getcwd() + "/TestResult")): 
		os.makedirs(path) 
	os.popen("adb wait-for-device") 
	time.sleep(1)#由於多次出現截圖延遲現象(每次截圖都截的是上次操作的畫面),故此處設置一個等待
	os.popen("adb shell screencap -p /data/local/tmp/tmp.png") 
	time.sleep(1)
	os.popen("adb pull /data/local/tmp/tmp.png " + PATH(path + "/"  + testcase + '.png')) 
	time.sleep(1)
	os.popen("adb shell rm /data/local/tmp/tmp.png") 
	time.sleep(1)
	im = Image.open(PATH(path + "/"  + testcase + '.png'))
	cropedIm = im.crop((0, 70, 1079,2080 ))
	cropedIm.save(PATH(path + "/"  + testcase + '.png'))
def compare_images(path_one, path_two, diff_save_location):
	"""
	比較圖片,如果有不同則生成展示不同的圖片

	@參數一: path_one: 第一張圖片的路徑
	@參數二: path_two: 第二張圖片的路徑
	@參數三: diff_save_location: 不同圖的保存路徑
	"""
	image_one = Image.open(path_one)
	image_two = Image.open(path_two)
	try: 
		diff = ImageChops.difference(image_one, image_two)
		if diff.getbbox() is None:
		# 圖片間沒有任何不同則直接退出
			return True
		else:
			diff.save(diff_save_location)
			return False
	except ValueError as e:
		text = ("表示圖片大小和box對應的寬度不一致,參考API說明:Pastes another image into this image."
				"The box argument is either a 2-tuple giving the upper left corner, a 4-tuple defining the left, upper, "
				"right, and lower pixel coordinate, or None (same as (0, 0)). If a 4-tuple is given, the size of the pasted "
				"image must match the size of the region.使用2緯的box避免上述問題")
		print("【{0}】{1}".format(e,text))


class Test(unittest.TestCase):
	def setUp(self):
		#appium 固定設置,沿用之前的即可
		self.desired_caps = {}
		self.desired_caps['platformName'] = 'Android'
		self.desired_caps['platformVersion'] = '9'
		self.desired_caps['deviceName'] = 'Android Emulator'
		self.desired_caps['appPackage'] = 'com.android.settings'
		self.desired_caps['appActivity'] = '.Settings$NetworkDashboardActivity'	
		self.desired_caps['noReset'] = 'true'
		self.driver = webdriver.Remote('http://localhost:4723/wd/hub', self.desired_caps)
	def test01(self):
		'''Network & internetEN01'''
		driver = self.driver
		driver.wait_activity(".Settings$NetworkDashboardActivity", 30)
		screenshot('test_NetworkEN01')
		driver.find_element_by_xpath("//*[@text='Advanced']").click()
		time.sleep(2)
		#講道理這個截圖應該放到test02里面的,只是跑邏輯,就懶得改了
		screenshot('test_NetworkEN02')
		time.sleep(5)
		#下面這個可以用參數來寫,會顯得短一些,懶得改了
		ac = compare_images('./TestResult/test_NetworkEN01.png','./DesiredResult/test_NetworkEN01.png','./DiffPicture/test_NetworkEN01.png')
		self.assertEqual(ac, True)
	def test02(self):
		'''Network & internetEN02'''
		bc = compare_images('./TestResult/test_NetworkEN02.png','./DesiredResult/test_NetworkEN02.png','./DiffPicture/test_NetworkEN02.png')
		self.assertEqual(bc, True)
		#clear envirment
	def tearDown(self):

		#self.assertTrue(ac != preStatus)
		self.driver.quit()
if __name__ == '__main__':
	unittest.main()

WlanUi.py 

 

#coding=utf-8

import time 
import unittest
from HTMLTestRunner import HTMLTestRunner
import os



if __name__=='__main__':   
    print ('=====AutoTest Start======')
    test_dir = './Test_case/'
    #知道測試報告的路徑
    test_report_dir='./testReport/'
    PATH = lambda p: os.path.abspath(p) 
    if not os.path.isdir(PATH(os.getcwd() + "/testReport")): 
        os.makedirs(test_report_dir) 
    discover=unittest.defaultTestLoader.discover(test_dir, pattern='test_*.py')
    now=time.strftime('%Y-%m-%d_%H_%M_%S_')
    filename = test_report_dir+'/'+ now + 'result.html'
    fp=open(filename ,'wb')
    
    runner = HTMLTestRunner(stream=fp,title=u'測試報告',description=u'用例執行情況:')
    runner.run(discover)

#注意:調用函數一定要加括號,一個括號害死個人,哎,查了幾天的問題,才發現導致html文件始終顯示空白,就是因為close函數調用不正確,漏了括號。
    fp.close() 
    
    #2.取最新測試報告
   # new_report=new_file(test_report_dir)
#調試用的
#    print new_report
    
    #3.發送郵件,發送最新測試報告html
  #  send_email(new_report)
    print('=====AutoTest Over======')
time.sleep(10)

    

左側是原始截圖,右側是截取的對比區域

 

 

   初次實現時, ImageChops.difference得到的截圖基本上看不清差異點,見下圖:

 

左側有張圖,但是看不清,使用ImageChops.invert 后變成這樣了

 

代碼:

def invert(im1):
	IM = Image.open(im1)
	im3 = ImageChops.invert(IM)
	im3.save('./DesiredResult/test_NetworkEN04.png')
	im3.close()

  

拼湊代碼查了多方資料,實在羅列不出各大大的鏈接,見諒!!

初次寫總結,感覺不怎么流暢,啥都想寫,尷尬得一撇

'''
以下為臨時筆記,備忘:
2.文件名以路徑首單詞為名字命名,eg:Sound/Display/Battery and so on
如下鏈接詳細介紹了ImageChops的使用
https://blog.csdn.net/icamera0/article/details/50727599
'''


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM