PyTest教程:什么是PyTest?(附示例)

⚡ 智能摘要

Pytest 是一个 Python 这是一个测试框架,可帮助您为数据库、API 和用户界面编写简单、可扩展的测试。它支持 fixtures、参数化、标记、并行运行和详细的断言报告,涵盖从基本单元测试到复杂功能测试的各种需求。

  • 🔘 安装方式: 命令 pip install pytest 添加框架,而 py.test -h 通过打印帮助输出来确认设置。
  • ☑️ 测试发现: Pytest 会自动收集名为 test_*.py 或 *_test.py 的文件以及名称以 test 开头的方法。
  • 断言: 普通的断言语句在检查失败时会报告一个清晰的 AssertionError 错误,其中包含比较的值。
  • 🧪 比赛时间: @pytest.fixture 装饰器提供可重用的设置数据,这些数据通过 conftest.py 文件在文件之间共享。
  • 🛠️ 选择性运行: 标记、-k 子字符串过滤器和参数化运行目标子集或在多个输入上运行相同的测试。
  • 🤖 人工智能工作流程: 机器学习团队使用 pytest 来验证数据管道和模型输出,而 Copilot 可以编写测试用例。

Pytest教程

pytest 是应用最广泛的测试框架之一 Python 生态系统。它能保持测试代码简洁易读,自动发现测试用例,并从最初的断言逐步发展成为涵盖数据库、API 和用户界面的完整测试套件。以下各节将通过实际示例,详细介绍安装、断言、测试夹具、标记、参数化和并行运行等内容。

什么是 Pytest?

pytest 是一个测试框架,它允许你使用以下方式编写测试代码 Python Pytest 是一种编程语言,它可以帮助您为数据库、API 甚至用户界面编写简单且可扩展的测试用例。Pytest 主要用于编写 API 测试,其功能范围从简单的单元测试到复杂的功能测试均可胜任。

为什么要使用 Pytest?

pytest 的一些优点包括:

  • 由于其语法简洁明了,因此非常容易上手。
  • 可以并行运行测试。
  • 可以运行特定测试或测试子集。
  • 自动检测测试。
  • 可以跳过测试。
  • 开源。

如何安装 Pytest

以下是安装 pytest 的步骤:

步骤1) 您可以使用以下命令安装 pytest。

pip install pytest==2.9.1

安装完成后,您可以使用以下命令进行确认。

py.test -h

这将显示帮助信息。

安装 pytest 并查看帮助输出

第一个基本的 Pytest 示例

现在,你将通过一个基本的 pytest 示例来学习如何使用 pytest。

创建一个名为 study_pytest 的文件夹。您将在该文件夹中创建测试文件。请在命令行中导航到该文件夹​​。在该文件夹内创建一个名为 test_sample1.py 的文件。

创建第一个基本的 pytest 测试文件

将以下代码添加到其中并保存。

import pytest
def test_file1_method1():
	x=5
	y=6
	assert x+1 == y,"test failed"
	assert x == y,"test failed"
def test_file1_method2():
	x=5
	y=6
	assert x+1 == y,"test failed" 

使用以下命令运行测试。

py.test

您将得到如下输出结果。

test_sample1.py F.
============================================== FAILURES ========================================
____________________________________________ test_sample1 ______________________________________
    def test_file1_method1():
    	x=5
    	y=6
       	assert x+1 == y,"test failed"
>      	assert x == y,"test failed"
E       AssertionError: test failed
E       assert 5 == 6
test_sample1.py:6: AssertionError

Pytest 测试失败输出

在 test_sample1.py 文件中,F 代表失败,点号 (.) 代表成功。在失败部分,您可以看到失败的方法以及失败的行。这里 x==y 表示 5==6,结果为假。

接下来,你将学习pytest中的断言。

Pytest 中的断言

Pytest 断言是返回 True 或 False 状态的检查。在 pytest 中,如果测试方法中的断言失败,则该方法的执行会立即停止。该测试方法中的剩余代码不会执行,pytest 会继续执行下一个测试方法。

Pytest 断言示例:

assert "hello" == "Hai" is an assertion failure.
assert 4==4 is a successful assertion
assert True is a successful assertion
assert False is an assertion failure.

考虑以下。

assert x == y,"test failed because x=" + str(x) + " y=" + str(y)

将此代码放入 test_file1_method1() 中,替换下面的断言。

assert x == y,"test failed"

运行测试将失败,如下所示 AssertionError:测试失败 x=5 y=6.

Pytest 如何识别测试文件和测试方法

默认情况下,pytest 只识别以 .pytest 开头的文件名。 测试_ 或以 _测试 作为测试文件。当然,我们也可以明确指定其他文件名(稍后会解释)。Pytest 要求测试方法名称以 `<path>` 开头。 实验所有其他方法名称都会被忽略,即使我们明确要求运行这些方法。

以下是一些有效和无效的pytest文件名示例。

test_login.py - valid
login_test.py - valid
testlogin.py -invalid
logintest.py -invalid

注意:是的,我们可以明确地要求 pytest 选择 testlogin.py 和 logintest.py。

请参阅一些有效和无效的 pytest 测试方法示例。

def test_file1_method1(): - valid
def testfile1_method1(): - valid
def file1_method1(): - invalid	

注意:即使我们明确地提到 file1_method1(),pytest 也不会运行此方法。

从特定文件和多个文件运行多个测试

目前,在 study_pytest 文件夹下有一个文件 test_sample1.py。假设我们有多个文件,例如 test_sample2.py 和 test_sample3.py。要运行该文件夹及其子文件夹中所有文件的所有测试,我们只需运行 pytest 命令即可。

py.test

这将运行该文件夹及其子文件夹中所有以 test_ 开头和以 _test 结尾的文件。

要仅从特定文件运行测试,我们可以使用 py.test。 。

py.test test_sample1.py

使用 Pytest 运行整个测试的子集

有时我们并不想运行整个测试套件。Pytest 允许我们运行特定的测试。我们可以通过两种方式实现:

  • 的Grouping 通过子字符串匹配筛选测试名称。
  • 的Grouping 按标记物进行测试。

我们已经有了 test_sample1.py 文件。创建一个名为 test_sample2.py 的文件,并将以下代码添加到其中。

def test_file2_method1():
	x=5
	y=6
	assert x+1 == y,"test failed"
	assert x == y,"test failed because x=" + str(x) + " y=" + str(y)
def test_file2_method2():
	x=5
	y=6
	assert x+1 == y,"test failed"

目前我们有以下情况。

• test_sample1.py
• test_file1_method1()
• test_file1_method2()
• test_sample2.py
• test_file2_method1()
• test_file2_method2()

选项 1)通过子字符串匹配运行测试

在这里,要运行所有名称中包含 method1 的测试,我们需要运行以下命令。

py.test -k method1 -v
-k <expression> is used to represent the substring to match
-v increases the verbosity

因此,运行 py.test -k method1 -v 将得到以下结果。

test_sample2.py::test_file2_method1 FAILED
test_sample1.py::test_file1_method1 FAILED

============================================== FAILURES ==============================================
_________________________________________ test_file2_method1 _________________________________________
    def test_file2_method1():
    	x=5
    	y=6
       	assert x+1 == y,"test failed"
>      	assert x == y,"test failed because x=" + str(x) + " y=" + str(y)
E       AssertionError: test failed because x=5 y=6
E       assert 5 == 6
test_sample2.py:5: AssertionError

_________________________________________ test_file1_method1 _________________________________________
    @pytest.mark.only
    def test_file1_method1():
    	x=5
    	y=6
       	assert x+1 == y,"test failed"
>      	assert x == y,"test failed because x=" + str(x) + " y=" + str(y)
E       AssertionError: test failed because x=5 y=6
E       assert 5 == 6
test_sample1.py:8: AssertionError

================================= 2 tests deselected by '-kmethod1' ==================================
=============================== 2 failed, 2 deselected in 0.02 seconds ===============================

在这里你可以看到,临近结尾时, 通过“-kmethod2”取消选择 1 个测试分别是 test_file1_method2 和 test_file2_method2。

尝试使用以下各种组合进行运行。

py.test -k method -v - will run all the four methods
py.test -k methods -v – will not run any test as there is no test name matches the substring 'methods'

选项 2)通过标记进行测试

Pytest 允许我们使用 `@pytest.mark` 标记为测试方法设置各种属性。要在测试文件中使用标记,我们需要将 pytest 导入到测试文件中。这里我们将为不同的测试方法应用不同的标记名称,并根据标记名称运行特定的测试。我们可以使用以下方法为每个测试名称定义标记。

@pytest.mark.<name>.			

我们在测试方法中定义了标记集 set1 和 set2,并将使用这些标记名称运行测试。请使用以下代码更新测试文件。

测试样本1.py

import pytest
@pytest.mark.set1
def test_file1_method1():
	x=5
	y=6
	assert x+1 == y,"test failed"
	assert x == y,"test failed because x=" + str(x) + " y=" + str(y)

@pytest.mark.set2
def test_file1_method2():
	x=5
	y=6
	assert x+1 == y,"test failed"

测试样本2.py

import pytest
@pytest.mark.set1
def test_file2_method1():
	x=5
	y=6
	assert x+1 == y,"test failed"
	assert x == y,"test failed because x=" + str(x) + " y=" + str(y)

@pytest.mark.set1
def test_file2_method2():
	x=5
	y=6
	assert x+1 == y,"test failed"

我们可以使用以下命令运行标记测试。

py.test -m <name>
-m <name> mentions the marker name

运行 py.test -m set1。这将运行 test_file1_method1、test_file2_method1 和 test_file2_method2 方法。运行 py.test -m set2 将运行 test_file1_method2。

使用 Pytest 并行运行测试

通常,一个测试套件会包含多个测试文件和数百个测试方法,执行起来会非常耗时。Pytest 允许我们并行运行测试。为此,我们需要先运行以下命令来安装 pytest-xdist。

pip install pytest-xdist

使用 pytest-xdist 并行运行测试

您现在可以使用以下命令运行测试。

py.test -n 4

这里,-n使用多个工作进程运行测试。在上述命令中,将有四个工作进程来运行测试。

Pytest Fixtures

当我们需要在每个测试方法之前运行一些代码时,就会使用 fixtures。这样,我们就不用在每个测试中重复编写相同的代码,而是定义 fixtures。通常,fixtures 用于初始化数据库连接、传递基础参数等。 URL等等。要将一个方法标记为 pytest fixture,请使用以下标记。

@pytest.fixture

测试方法可以通过将测试夹具作为输入参数来使用它。创建一个新文件 test_basic_fixture.py,并添加以下代码。

import pytest
@pytest.fixture
def supply_AA_BB_CC():
	aa=25
	bb =35
	cc=45
	return [aa,bb,cc]

def test_comparewithAA(supply_AA_BB_CC):
	zz=35
	assert supply_AA_BB_CC[0]==zz,"aa and zz comparison failed"

def test_comparewithBB(supply_AA_BB_CC):
	zz=35
	assert supply_AA_BB_CC[1]==zz,"bb and zz comparison failed"

def test_comparewithCC(supply_AA_BB_CC):
	zz=35
	assert supply_AA_BB_CC[2]==zz,"cc and zz comparison failed"

这里:

  • 我们有一个名为 supply_AA_BB_CC 的夹具。此方法返回一个包含三个值的列表。
  • 我们采用了三种测试方法,分别与每个值进行比较。

每个测试函数都有一个输入参数,其名称与一个可用的 fixture 相匹配。Pytest 会调用相应的 fixture 方法,并将返回值存储在输入参数中,这里是列表 [25, 35, 45]。然后,这些列表项会在测试方法中用于比较。现在运行测试并查看结果。

 py.test test_basic_fixture
test_basic_fixture.py::test_comparewithAA FAILED                                                                                                                                                                                       
test_basic_fixture.py::test_comparewithBB PASSED                                                                                                                                                                                       
test_basic_fixture.py::test_comparewithCC FAILED
                                                                                                                                                                                       
============================================== FAILURES ==============================================
_________________________________________ test_comparewithAA _________________________________________
supply_AA_BB_CC = [25, 35, 45]
    def test_comparewithAA(supply_AA_BB_CC):
    	zz=35
>   	assert supply_AA_BB_CC[0]==zz,"aa and zz comparison failed"
E    AssertionError: aa and zz comparison failed
E    assert 25 == 35
test_basic_fixture.py:10: AssertionError

_________________________________________ test_comparewithCC _________________________________________
supply_AA_BB_CC = [25, 35, 45]
    def test_comparewithCC(supply_AA_BB_CC):
    	zz=35
>   	assert supply_AA_BB_CC[2]==zz,"cc and zz comparison failed"
E    AssertionError: cc and zz comparison failed
E    assert 45 == 35
test_basic_fixture.py:16: AssertionError
================================= 2 failed, 1 passed in 0.05 seconds =================================

测试 test_comparewithBB 通过,因为 zz=BB=35,其余两个测试失败。

fixture 方法的作用域仅限于定义它的测试文件。如果我们尝试在其他测试文件中访问 fixture,将会收到一个错误,提示 fixture 存在问题。 未找到“supply_AA_BB_CC” 用于其他文件中的测试方法。

要对多个测试文件使用相同的 fixture,我们需要在名为 conftest.py 的文件中创建 fixture 方法。让我们通过下面的 pytest 示例来了解一下。创建三个文件:conftest.py、test_basic_fixture.py 和 test_basic_fixture2.py,并添加以下代码。

conftest.py

import pytest
@pytest.fixture
def supply_AA_BB_CC():
	aa=25
	bb =35
	cc=45
	return [aa,bb,cc]

测试基本装置.py

import pytest
def test_comparewithAA(supply_AA_BB_CC):
	zz=35
	assert supply_AA_BB_CC[0]==zz,"aa and zz comparison failed"

def test_comparewithBB(supply_AA_BB_CC):
	zz=35
	assert supply_AA_BB_CC[1]==zz,"bb and zz comparison failed"

def test_comparewithCC(supply_AA_BB_CC):
	zz=35
	assert supply_AA_BB_CC[2]==zz,"cc and zz comparison failed"

测试基本装置2.py

import pytest
def test_comparewithAA_file2(supply_AA_BB_CC):
	zz=25
	assert supply_AA_BB_CC[0]==zz,"aa and zz comparison failed"

def test_comparewithBB_file2(supply_AA_BB_CC):
	zz=25
	assert supply_AA_BB_CC[1]==zz,"bb and zz comparison failed"

def test_comparewithCC_file2(supply_AA_BB_CC):
	zz=25
	assert supply_AA_BB_CC[2]==zz,"cc and zz comparison failed"

Pytest 首先会在测试文件中查找 fixture,如果找不到,则会在 conftest.py 中查找。使用 py.test -k test_comparewith -v 运行测试,即可获得以下结果。

test_basic_fixture.py::test_comparewithAA FAILED  
test_basic_fixture.py::test_comparewithBB PASSED 
test_basic_fixture.py::test_comparewithCC FAILED 
test_basic_fixture2.py::test_comparewithAA_file2 PASSED 
test_basic_fixture2.py::test_comparewithBB_file2 FAILED 
test_basic_fixture2.py::test_comparewithCC_file2 FAILED

Pytest 参数化测试

参数化测试的目的是针对多组参数运行测试。我们可以使用 `@pytest.mark.parametrize` 来实现这一点。以下 pytest 示例将对此进行演示。这里我们将向一个测试方法传递三个参数。该测试方法会将前两个参数相加,并将结果与​​第三个参数进行比较。创建测试文件 `test_addition.py`,并添加以下代码。

import pytest
@pytest.mark.parametrize("input1, input2, output",[(5,5,10),(3,5,12)])
def test_add(input1, input2, output):
	assert input1+input2 == output,"failed"

这里的测试方法接受三个参数:input1、input2 和 output。它将 input1 和 input2 相加,并将和与 output 进行比较。让我们使用 `py.test -k test_add -v` 运行测试并查看结果。

test_addition.py::test_add[5-5-10] PASSED                                                                                                                                                                                              
test_addition.py::test_add[3-5-12] FAILED                                                                                                                                                                                              
============================================== FAILURES ==============================================
__________________________________________ test_add[3-5-12] __________________________________________
input1 = 3, input2 = 5, output = 12
    @pytest.mark.parametrize("input1, input2, output",[(5,5,10),(3,5,12)])
    def test_add(input1, input2, output):
>   	assert input1+input2 == output,"failed"
E    AssertionError: failed
E    assert (3 + 5) == 12
test_addition.py:5: AssertionError

你可以看到测试运行了两次,一次检查 5+5 ==10,另一次检查 3+5 ==12。

test_addition.py::test_add[5-5-10]已通过

test_addition.py::test_add[3-5-12] 失败

Pytest Xfail 和 Skip 测试

有些情况下,我们可能不想执行测试,或者…… 测试用例 在特定时间点,该测试并不相关。在这种情况下,我们可以选择将测试标记为失败(xfail)或跳过测试。标记为失败的测试将会执行,但不会被计入失败或通过的测试总数中。不会有任何 trac如果测试失败,则会显示 eback。我们可以使用 @pytest.mark.xfail 来对测试进行 xfail 标记。跳过ping 测试结果为“未执行”意味着该测试不会被执行。我们可以使用 `@pytest.mark.skip` 跳过测试。请将以下代码添加到 `test_addition.py` 文件中。

import pytest
@pytest.mark.skip
def test_add_1():
	assert 100+200 == 400,"failed"

@pytest.mark.skip
def test_add_2():
	assert 100+200 == 300,"failed"

@pytest.mark.xfail
def test_add_3():
	assert 15+13 == 28,"failed"

@pytest.mark.xfail
def test_add_4():
	assert 15+13 == 100,"failed"

def test_add_5():
	assert 3+2 == 5,"failed"

def test_add_6():
	assert 3+2 == 6,"failed"

这里:

  • test_add_1 和 test_add_2 被跳过,不会被执行。
  • test_add_3 和 test_add_4 被标记为 xfailed。这些测试将会执行,并分别计入 xfailed(测试失败)或 xpassed(测试通过)的测试结果中。不会有任何 trac失败后可获得退款。
  • test_add_5 和 test_add_6 将会执行,test_add_6 将报告失败。 trac当 test_add_5 通过时,eback。

使用 py.test test_addition.py -v 执行测试并查看结果。

test_addition.py::test_add_1 SKIPPED
test_addition.py::test_add_2 SKIPPED
test_addition.py::test_add_3 XPASS
test_addition.py::test_add_4 xfail
test_addition.py::test_add_5 PASSED
test_addition.py::test_add_6 FAILED

============================================== FAILURES ==============================================
_____________________________________________ test_add_6 _____________________________________________
    def test_add_6():
>   	assert 3+2 == 6,"failed"
E    AssertionError: failed
E    assert (3 + 2) == 6
test_addition.py:24: AssertionError

================ 1 failed, 1 passed, 2 skipped, 1 xfailed, 1 xpassed in 0.07 seconds =================

结果以 XML 格式呈现

我们可以将测试结果生成为 XML 格式,并将其提供给持续集成服务器进行进一步处理。这可以通过命令 `py.test test_sample1.py -v --junitxml=”result.xml”` 来实现。`result.xml` 文件将记录测试执行结果。以下是一个 `result.xml` 示例。

<?xml version="1.0" encoding="UTF-8"?>
<testsuite errors="0" failures="1" name="pytest" skips="0" tests="2" time="0.046">
   <testcase classname="test_sample1" file="test_sample1.py" line="3" name="test_file1_method1" time="0.001384973526">
     <failure message="AssertionError:test failed because x=5 y=6 assert 5 ==6">
    @pytest.mark.set1
    def test_file1_method1():
    	x=5
    	y=6
       	assert x+1 == y,"test failed"
>      	assert x == y,"test failed because x=" + str(x) + " y=" + str(y)
E       AssertionError: test failed because x=5 y=6
E       assert 5 == 6
         test_sample1.py:9: AssertionError
    </failure>
   </testcase>
   <testcase classname="test_sample1" file="test_sample1.py" line="10" name="test_file1_method2" time="0.000830173492432" />
</testsuite>

从我们可以看到总共有两个测试,其中一个失败了。下方可以看到每个已执行测试的详细信息。标签。

用于测试 API 的 Pytest 框架

现在我们将创建一个简单的 pytest 框架来测试一个 API。这里使用的 API 是一个免费的 API。 请求本网站仅提供可测试的 API,并不存储我们的数据。接下来,我们将编写一些针对以下内容的测试:

  • 列出部分用户。
  • 使用用户登录。

使用给定的代码创建以下文件。首先,conftest.py 包含一个 fixture,它将提供基础测试结果。 URL 适用于所有测试方法。

import pytest
@pytest.fixture
def supply_url():
	return "https://reqres.in/api"

接下来,test_list_user.py 包含列出有效用户和无效用户的测试方法。

  • test_list_valid_user 测试用户获取是否有效并验证响应。
  • test_list_invaliduser 测试无效用户获取并验证响应。
import pytest
import requests
import json
@pytest.mark.parametrize("userid, firstname",[(1,"George"),(2,"Janet")])
def test_list_valid_user(supply_url,userid,firstname):
	url = supply_url + "/users/" + str(userid)
	resp = requests.get(url)
	j = json.loads(resp.text)
	assert resp.status_code == 200, resp.text
	assert j['data']['id'] == userid, resp.text
	assert j['data']['first_name'] == firstname, resp.text

def test_list_invaliduser(supply_url):
	url = supply_url + "/users/50"
	resp = requests.get(url)
	assert resp.status_code == 404, resp.text

然后,test_login_user.py 包含用于测试登录功能的测试方法。

  • test_login_valid 测试使用电子邮件和密码进行有效的登录尝试。
  • test_login_no_password 测试不提供密码的无效登录尝试。
  • test_login_no_email 测试不提供电子邮件地址的无效登录尝试。
import pytest
import requests
import json
def test_login_valid(supply_url):
	url = supply_url + "/login/" 
	data = {'email':'test@test.com','password':'something'}
	resp = requests.post(url, data=data)
	j = json.loads(resp.text)
	assert resp.status_code == 200, resp.text
	assert j['token'] == "QpwL5tke4Pnpja7X", resp.text

def test_login_no_password(supply_url):
	url = supply_url + "/login/" 
	data = {'email':'test@test.com'}
	resp = requests.post(url, data=data)
	j = json.loads(resp.text)
	assert resp.status_code == 400, resp.text
	assert j['error'] == "Missing password", resp.text

def test_login_no_email(supply_url):
	url = supply_url + "/login/" 
	data = {}
	resp = requests.post(url, data=data)
	j = json.loads(resp.text)
	assert resp.status_code == 400, resp.text
	assert j['error'] == "Missing email or username", resp.text

使用 py.test -v 运行测试,结果如下所示。

test_list_user.py::test_list_valid_user[1-George] PASSED                                                                                                                                                                               
test_list_user.py::test_list_valid_user[2-Janet] PASSED                                                                                                                                                                                
test_list_user.py::test_list_invaliduser PASSED                                                                                                                                                                                        
test_login_user.py::test_login_valid PASSED                                                                                                                                                                                            
test_login_user.py::test_login_no_password PASSED                                                                                                                                                                                      
test_login_user.py::test_login_no_email PASSED

更新测试并尝试不同的输出结果。

常见问题

两者都运行 Python 虽然 Pytest 也支持测试,但它使用简单的断言语句,样板代码更少,并且提供了 fixtures、markers 和 parametrize 功能。Unittest 包含在标准库中,并遵循基于类的 xUnit 风格。Pytest 仍然可以运行现有的 unittest 测试用例。

使用双冒号作为节点 ID 语法:`pytest test_sample1.py::test_file1_method1`。这将只运行该方法。您也可以针对整个文件(`pytest test_sample1.py`)或使用 `-k` 选项按名称筛选。

安装 pytest-cov 插件,然后运行 ​​pytest --cov=your_package。它会报告测试执行的代码行百分比,而 --cov-report=html 会生成一个可浏览的报告,其中突出显示未测试的代码行。

fixture 的作用域控制其运行频率:函数(默认)、类、模块、包或会话。使用 `@pytest.fixture(scope=”module”)` 设置。更广泛的作用域会在多个测试中复用耗时的设置,例如数据库连接。

运行 `pytest -x` 可以在第一个测试失败后立即停止,或者运行 `pytest --maxfail=2` 可以在指定数量的测试失败后停止。这可以缩短调试故障测试套件时的反馈循环。

Pytest 默认会捕获标准输出。添加 `-s` 标志(`pytest -s`)可以禁用捕获并实时显示打印语句。`-v` 标志会添加详细的测试输出,列出每个测试的名称及其结果。

机器学习团队使用 pytest 来验证数据加载管道、特征转换和模型输出。测试用例提供示例数据集,并对许多输入进行参数化检查,从而确保系统的智能部分在代码更改时保持可靠性。

是的。GitHub Copilot 和智能 AI 助手可以根据简短的提示或现有函数生成 pytest 函数、测试用例和参数化用例。 Rev查看生成的断言,因为人工智能可能会遗漏极端情况并误判预期值。

总结一下这篇文章: