编程语言
首页 > 编程语言> > 为什么模拟数据对于测试来说是一种不好的做法

为什么模拟数据对于测试来说是一种不好的做法

作者:互联网

模拟数据是测试依赖于外部数据源(例如数据库、Web 服务或 API)的软件的常用技术。模拟数据意味着创建模仿真实数据的虚假或模拟数据,但实际上不与外部源交互。模拟数据对于某些场景很有用,例如:

然而,模拟数据也有一些严重的缺点和风险,例如:

在这篇博文中,我将认为模拟数据对于测试软件来说是一种不好的做法,您应该尽可能避免它。我还将向您展示一些示例,说明如何使用 Python 和 PyTest 测试依赖于外部数据源的软件而不模拟数据。

模拟数据的示例

假设我们有一个函数可以根据在线商店的评论计算产品的平均评分。该函数将产品 ID 作为输入,并返回平均评分作为输出。该函数使用 API 从在线商店获取评论。

import requests 

def  get_average_ rating ( product_id ): 
    """
    根据在线商店的评论返回产品的平均评分。 """ 
    url
     = f"https://online-store.com/api/reviews/ {product_id } "
     response = requests.get(url) 
    if response.status_code == 200 : 
        Reviews = response.json() 
        ratings = [review[ " rating" ] for review in Reviews] 
        average_ rating = sum (patings) / len ( ratings)
        返回average_ rating 
    else : 
        raise Exception( f"无法获得产品{product_id}的评论" )

为了测试这个函数,我们可能会想使用像unittest.mock或pytest-mock这样的库来模拟API返回的数据。例如,我们可以编写这样的测试:

import pytest 
from pytest_mock import mocker 
fromaverage_ rating import get_average_ rating 

def  test_get_average_ rating ( mocker ): 
    # 排列
    product_id = 123
     mock_reviews = [ 
        { " rating" : 5 , "comment" : "很棒的产品!" }, 
        { "评分" : 4 , "评论" : "质量好。" }, 
        { “评级” : 3 ,“评论”“还不错。” } 
    ]
    预期平均评级 = 4.0
     mocker.patch( "requests.get" ) 
    requests.get.return_value.status_code = 200
     requests.get.return_value.json.return_value = mock_reviews 

    #
执行    actual_average_ rating = get_average_ rating(product_id) 

    # 断言
    assertactual_average_ rating == Expected_average_ rating

此测试为 requests.get 创建一个模拟对象,并设置其返回值以模仿 API 的成功响应以及一些虚假评论。然后它调用被测函数并断言它返回预期的平均评级。

模拟数据的问题

乍一看,这个测试似乎没问题。运行速度快,通过,并且涵盖了函数的主要逻辑。然而,该测试存在几个问题,使其不可靠且无效。

测试不是测试真实数据

第一个问题是测试不是测试来自API的真实数据,而只是测试它的模拟版本。这意味着模拟数据和真实数据之间可能存在差异或差异,这可能会影响函数的行为或结果。

例如,如果真正的 API 返回的字段不仅仅是评级和评论怎么办?如果函数需要或使用其中一些字段怎么办?如果其中一些字段的名称或类型与预期不同怎么办?如果其中一些字段具有无效或意外值怎么办?

所有这些场景都可能导致函数中的错误或错误,而测试无法检测到这些错误或错误,因为它仅使用数据的简化版本。即使函数在使用真实数据时失败,测试也会通过。

该测试不是测试与外部源的交互

第二个问题是测试不是测试与外部源的交互,而只是测试它的模拟版本。这意味着与 API 的通信或集成可能会出现问题或失败,从而影响函数的行为或结果。

例如,如果 API 关闭或不可用怎么办?如果 API 缓慢或无响应怎么办?如果 API 返回错误或状态代码与预期不同怎么办?如果 API 在没有通知的情况下更改其格式或结构怎么办?

所有这些场景都可能导致函数中出现测试无法检测到的错误或错误,因为它仅使用响应的模拟版本。即使函数在使用真实数据时失败,测试也会通过。

测试难以维护和更新

第三个问题是测试很难维护和更新,因为它需要额外的代码和逻辑来创建和管理模拟数据。这意味着测试代码本身可能存在错误或不一致,从而影响测试的可靠性或有效性。

例如,如果模拟数据已过时或不正确怎么办?如果模拟数据不完整或缺少某些案例怎么办?如果不同测试中的模拟数据重复或不一致怎么办?如果模拟数据难以阅读或理解怎么办?

所有这些情况都可能导致测试代码中出现错误或错误,从而影响测试结果。测试可能因错误原因而失败或通过。

如何在不模拟数据的情况下进行测试

那么,我们如何在不模拟数据的情况下测试依赖于外部数据源的软件呢?根据上下文和数据源的性质,有多种可能的解决方案。以下是一些一般准则和提示:

让我们看看如何将这些解决方案应用到测试函数的示例中,该函数根据在线商店的评论计算产品的平均评分。

使用真实数据源

一种选择是使用提供产品评论的真实在线商店 API。例如,我们可以使用亚马逊的产品广告 API,它允许我们搜索产品并获取其评级和评论。要使用此 API,我们需要注册一个帐户并获取访问密钥和秘密密钥。

我们还需要稍微修改我们的函数以使用这个 API 而不是假的:

import requests 
from amazon.paapi import AmazonAPI 

def  get_average_ rating ( product_id ): 
    """根据来自 Amazon 的评论返回产品的平均评分。"""
     amazon = AmazonAPI(ACCESS_KEY, SECRET_KEY) 
    Product = amazon.get_product(product_id) 
    Reviews = Product.reviews 
    ratings = [review[ " rating" ]用于评论中的评论] 
    average_ rating = sum ( ratings ) / len ( ratings ) 
    returnaverage_ rating

然后我们可以编写这样的测试:

import pytest 
from Average_Rating import get_average_Rating 

def  test_get_average_Rating (): # 排列    Product_id = "B07XJ8C8F5" # 来自 Amazon 的随机产品Expected_average_Rating     = 4.6 # 来自 Amazon 的实际平均Rating #     Actual_average_Rating = get_average_Rating(Product_id) # Assert assertactual_average_Rating == Expected_average_Ring

该测试的优点在于它使用真实数据以及与外部源的真实交互,这增加了其覆盖范围和置信度。缺点是它依赖于可能不可用或不可靠的外部源,这会降低其速度和稳定性。

使用本地数据源

另一种选择是使用包含产品评论的本地数据库。例如,我们可以使用 SQLite,它是一个轻量级且独立的数据库引擎,可以在内存中运行。要使用 SQLite,我们需要安装它并创建一个包含一些示例数据的数据库文件。

我们还需要稍微修改我们的函数以使用 SQLite 而不是假 API:

import sqlite3 

def  get_average_ rating ( product_id ): 
    """根据本地数据库的评论返回产品的平均评分。"""
     conn = sqlite3.connect( "reviews.db" ) 
    Cursor = conn.cursor() 

    #在数据库中查询产品的评论 query
     = "SELECT rating FROM Reviews WHERE Product_id = ?" 
    Cursor.execute(query, (product_id,)) 
    Reviews = Cursor.fetchall() 

    # 计算平均评分
    ratings = [review[ 0 ] for review in Reviews] 
    average_ rating = sum( ratings) / len ( ratings) 

    # 关闭连接
    conn.close() 

    returnaverage_ rating

然后我们可以编写这样的测试:

import pytest 
from Average_Rating import get_average_Rating 

def  test_get_average_Rating (): 
    # 排列
    Product_id = 123  # 数据库中的随机产品
    Expected_average_Rating = 4.0  # 数据库中的实际平均评级

    #
     Actual_average_Rating = get_average_Rating(Product_id) 

    # Assert 
    assertactual_average_Rating == Expected_average_Rating

此测试使用数据库中的真实产品 ID,并检查函数返回的平均评分是否与数据库中存储的平均评分相同。

该测试的优点是它使用真实数据并与本地源进行真实交互,这提高了其速度和稳定性。缺点是它需要一些额外的设置和配置,并且可能与外部源不兼容或一致。

标签:软件工程,软件开发, 开发运营
来源: