基于 AI 识别方法的自动化测试
目录
- 课程目标
- 应用场景
- AI 文字识别与自动化测试
课程目标
-
掌握自动化过程中验证码的获取方式。
-
L1.用例录制与编写
- L2.高级定位与 PO 设计模式
- L3.webview 与微信小程序测试
- L4.Appium 源码分析与定制
- L5.分布式测试与多设备管理【当前阶段】
思考
自动化登录时验证码如何获取?

AI 识别简介
- AI(Artificial Intelligence),指的是人工智能
- 提取处理图像
- 特征检测
- 图像分割
- 图像恢复
- 图像压缩
常见 AI 识别深度学习框架
- OpenCV
- 跨平台计算机视觉和机器学习软件库。
- 实现了图像处理和计算机视觉方面的很多通用算法。
- PyTorch
- Facebook 开发的一个开源深度学习框架。
- 开源的 Python 机器学习库。
- TensorFlow
- Google Brain 团队开发的一个开源深度学习框架。
- 基于数据流编程的符号数学系统。
- 用于各类机器学习算法的编程实现。
演练环境
- 霍格沃兹测试开发学社演练环境:
- https://vip.ceshiren.com/#/ui_study/code
实现思路
未使用 AI 处理(Python)
- Python 环境准备:
pip install opencv-python pip install "opencv-python-headless<4.3"
# 不加 AI 处理的场景,用例失败
def test_code(self):
# 获取验证码图片链接
img_url = self.driver.find_element(By.CSS_SELECTOR, ".code1:nth-child(1) img").get_attribute("src")
# 获取验证码内容
code = OcrCode.get_by_ocr(img_url)
# 输入验证码
self.driver.find_element(By.CSS_SELECTOR, ".code1:nth-child(1) input").send_keys(code)
# 点击确认
self.driver.find_element(By.CSS_SELECTOR, ".code1:nth-child(1) button").click()
sleep(1)
# 断言验证码是否正确
text = self.driver.find_element(By.CSS_SELECTOR, ".el-message p").text
print(text)
assert text == "验证成功"
使用 OpenCv + EasyOCR 进行文字识别(Python)
# ocr_code.py
class OcrCode:
@classmethod
def get_by_ocr(cls, img_url):
# 使用requests发请求拿到图片结果
result = requests.get(img_url, verify=False)
# 保存图片到本地
with open("code.png", "wb") as f:
f.write(result.content)
sleep(2)
# 实例化easyocr
ocr = easyocr.Reader(['ch_sim', 'en'])
# 识别图片内容
code = ocr.readtext("code.png")[0][1]
print(f"识别到的验证码为:{code}")
# opencv处理图片
cls.opencv_image()
# 实例化easyocr
ocr = easyocr.Reader(['ch_sim', 'en'])
# 识别图片内容
code = ocr.readtext("result.png")[0][1].replace(" ", "")
print(f"识别到的验证码为:{code}")
return code
@classmethod
def opencv_image(cls):
# 读取图片
image = cv2.imread("code.png")
# 边缘保留滤波 去噪
image1 = cv2.pyrMeanShiftFiltering(image, sp=8, sr=60)
# 灰度图像,颜色处理
image2 = cv2.cvtColor(image1, cv2.COLOR_BGR2GRAY)
# 颜色取反
cv2.bitwise_not(image2, image2)
# 保存图片
cv2.imwrite('result.png', image2)
# test_code.py
class TestCode:
def setup_class(self):
self.driver = webdriver.Chrome()
self.driver.implicitly_wait(10)
# 打开页面
self.driver.get("https://vip.ceshiren.com/#/ui_study/code")
def teardown_class(self):
self.driver.quit()
def test_code_by_ocr(self):
# 获取验证码图片链接
img_url = self.driver.find_element(By.CSS_SELECTOR, ".code1:nth-child(1) img").get_attribute("src")
# 获取验证码内容
code = OcrCode.get_by_ocr(img_url)
# 输入验证码
self.driver.find_element(By.CSS_SELECTOR, ".code1:nth-child(1) input").send_keys(code)
# 点击确认
self.driver.find_element(By.CSS_SELECTOR, ".code1:nth-child(1) button").click()
sleep(1)
# 断言验证码是否正确
text = self.driver.find_element(By.CSS_SELECTOR, ".el-message p").text
print(text)
assert text == "验证成功"
未使用 AI 处理(Java)
- 对于简单的验证码,只需要使用 easyocr 就可以很轻松地识别出来。
- 对于复杂验证码(倾斜,背景,重叠等),需要先使用 OpenCV 对图像处理,再用 easyocr 识别
@Test
public void registerByOcr() throws IOException, InterruptedException {
// 获取验证码图片链接
String imgUrl = driver.findElement(By.cssSelector(".code1:nth-child(1) img")).getAttribute("src");
// 获取验证码内容
String code = OcrCode.getByOcr(imgUrl);
// 输入验证码
driver.findElement(By.cssSelector(".code1:nth-child(1) input")).sendKeys(code);
// 点击确认
driver.findElement(By.cssSelector(".code1:nth-child(1) button")).click();
sleep(1000);
// 断言验证码是否正确
String text = driver.findElement(By.cssSelector(".el-message p")).getText();
System.out.println(text);
assertNotEquals("验证成功", text);
}
使用 OpenCv + EasyOCR 进行文字识别(Java)
// OcrCode.java
public class OcrCode {
public static String getByOcr(String imgUrl) throws IOException {
// 使用restassured发请求拿到图片结果
Response response = given().get(imgUrl).then().extract().response();
// 图片保存的目录和文件名
File input = new File("code.png");
FileOutputStream fos = new FileOutputStream(input);
// 将图片保存到文件
fos.write(response.getBody().asByteArray());
fos.close();
EasyOCR e=new EasyOCR();
//直接识别图片内容
System.out.println("直接识别图片内容");
System.out.println(e.discern(input));
// opencv处理图片
opencvImg();
String code = e.discern(new File("result.png"));
System.out.println("opencv处理图片");
System.out.println(code);
return code;
}
public static void opencvImg(){
System.load("D:\\ceba\\javaProject\\src\\main\\resources\\opencv_java340-x64.dll");
Mat image = Imgcodecs.imread("code.png");
// 边缘保留滤波 去噪
Mat image1 = new Mat();
Imgproc.pyrMeanShiftFiltering(image, image1, 8, 60, 150);
// 灰度图像,颜色处理
Mat image2 = new Mat();
Imgproc.cvtColor(image1, image2, Imgproc.COLOR_BGR2GRAY);
// 保存图片
Imgcodecs.imwrite("result.png", image2);
}
}
// CodeTest.java
class CodeTest {
public static ChromeDriver driver;
@BeforeAll
public static void beforeAll() {
ChromeOptions option = new ChromeOptions();
option.addArguments("--remote-allow-origins=*");
driver = new ChromeDriver(option);
// 隐式等待
driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(10));
driver.get("https://vip.ceshiren.com/#/ui_study/code");
}
@AfterAll
public static void afterAll() {
driver.quit();
}
@Test
public void registerByOcr() throws IOException, InterruptedException {
// 获取验证码图片链接
String imgUrl = driver.findElement(By.cssSelector(".code1:nth-child(1) img")).getAttribute("src");
// 获取验证码内容
String code = OcrCode.getByOcr(imgUrl);
// 输入验证码
driver.findElement(By.cssSelector(".code1:nth-child(1) input")).sendKeys(code);
// 点击确认
driver.findElement(By.cssSelector(".code1:nth-child(1) button")).click();
sleep(1000);
// 断言验证码是否正确
String text = driver.findElement(By.cssSelector(".el-message p")).getText();
System.out.println(text);
assertNotEquals("验证成功", text);
}
}
总结
源码地址
附录:完整依赖配置(Python)
async-generator==1.10
attrs==23.1.0
certifi==2022.12.7
cffi==1.15.1
charset-normalizer==3.1.0
colorama==0.4.6
easyocr==1.6.2
exceptiongroup==1.1.1
filelock==3.12.0
h11==0.14.0
idna==3.4
imageio==2.28.1
iniconfig==2.0.0
Jinja2==3.1.2
lazy_loader==0.2
MarkupSafe==2.1.2
mpmath==1.3.0
networkx==3.1
ninja==1.11.1
numpy==1.24.3
opencv-python==4.7.0.72
opencv-python-headless==3.4.18.65
outcome==1.2.0
packaging==23.1
Pillow==9.5.0
pluggy==1.0.0
pyclipper==1.3.0.post4
pycparser==2.21
PySocks==1.7.1
pytest==7.3.1
python-bidi==0.4.2
PyWavelets==1.4.1
PyYAML==6.0
requests==2.28.2
scikit-image==0.20.0
scipy==1.10.1
selenium==4.9.0
shapely==2.0.1
six==1.16.0
sniffio==1.3.0
sortedcontainers==2.4.0
sympy==1.11.1
tifffile==2023.4.12
tomli==2.0.1
torch==2.0.0
torchvision==0.15.1
trio==0.22.0
trio-websocket==0.10.2
typing_extensions==4.5.0
urllib3==1.26.15
wsproto==1.2.0
附录:完整依赖配置(Java)
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>javaProject</artifactId>
<groupId>com.ceshiren</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>AiCode</artifactId>
<properties>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<!--junit5-->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<!--对应添加的依赖的作用范围-->
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.platform</groupId>
<artifactId>junit-platform-suite</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
<scope>test</scope>
</dependency>
<!--hamcrest断言-->
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest</artifactId>
<version>2.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-core</artifactId>
<version>2.2</version>
<scope>test</scope>
</dependency>
<!-- selenium-->
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-java</artifactId>
<version>4.3.0</version>
</dependency>
<!-- rest-assured -->
<dependency>
<groupId>io.rest-assured</groupId>
<artifactId>rest-assured</artifactId>
<version>4.4.0</version>
<scope>compile</scope>
</dependency>
<!-- easyocr依赖 -->
<dependency>
<groupId>cn.easyproject</groupId>
<artifactId>easyocr</artifactId>
<version>3.0.4-RELEASE</version>
</dependency>
<!-- opencv依赖 -->
<dependency>
<groupId>org.bytedeco</groupId>
<artifactId>opencv</artifactId>
<version>4.6.0-1.5.8</version>
</dependency>
</dependencies>
</project>