基於LangChain手工測試用例轉介面自動化測試生成工具

霍格沃兹测试开发学社發表於2024-08-16

介面自動化測試用例是一個老生常談的問題,在未引入人工智慧之前,也有非常多的生成方案,比如如下所示,透過har生成介面自動化測試用例:

但是以上的生成方式依然是有一些弊端,比如 har 本身雖然能表述一定的介面資訊和業務資訊,但是畢竟無法用來表述全部的應用場景與用例場景。而大部分的應用場景和用例場景,均是透過自然語言進行描述的。而解析自然語言,則是大語言模型擅長做的事情。

實踐演練

需求說明

以下內容為3條介面測試用例:

測試模組 測試標題 測試步驟 預期結果
介面功能 正常情況下的請求 傳送一個正常的GET請求 響應狀態碼為 200 ,並返回請求者的IP地址
介面功能 非法請求方法 傳送一個非GET請求,如POST或者PUT 響應狀態碼為 405
介面功能 無效的請求路徑 傳送一個不存在的路徑 響應狀態碼為404

以下為一個獲取ip介面的har檔案:

  • 介面Har檔案(需要可留言領取)

實現原理

接下來,將透過這兩個資料檔案自動生成對應的測試用例。

透過功能用例生成測試指令碼

在這個過程中,測試用例本身是自然語言,自然語言的解析與處理本身就是大模型非常擅長的工作。而可以透過 LangChain 簡化整個的實現的過程。

編寫的提示詞模版資訊如下所示:

template = """
你是一個自動化測試工程師,精通的技術棧為 Python pytest requests庫
以下是這個介面的具體資訊,

{context}

Question: {input}"""

透過功能測試用例生成的自動化測試指令碼如下所示:


#1. Test case: 正常情況下的請求
import pytest
import requests

def test_normal_request():
    url = 'http://example.com/normal_request'
    response = requests.get(url)
    assert response.status_code == 200
    assert response.json()['ip_address'] == 'requester_ip'
#2. Test case: 非法請求方法
import pytest
import requests
def test_invalid_request_method():
    url = 'http://example.com/invalid_request_method'
    response = requests.post(url)
    assert response.status_code == 405
# 3. Test case: 無效的請求路徑
import pytest
import requests
def test_invalid_request_path():
    url = 'http://example.com/invalid_request_path'
    response = requests.get(url)
    assert response.status_code == 404

當然,在此過程中可以很明顯的發現,自動生成的用例是沒有任何的介面資訊的。原因是我們給到的資料裡面就是沒有介面資訊的。

填充介面資料

接下來,將讀取har檔案中的介面資料資訊,和指令碼進行結合。

提示詞模版如下:


template = """
    你是一個自動化測試工程師,你非常熟悉requests庫
    {context}
    Question: 
    請根據傳入的介面資訊提取request中的 ip 、 url 、method、json。
    key值為前面提到的欄位,如果沒有則無需新增。如果有則提取對應的value。
    要求返回的格式為json格式
"""

生成結果如下:

{
  "ip": "182.92.156.22",
  "url": "https://httpbin.ceshiren.com/ip",
  "method": "GET"
}

完整程式碼

再將以上的過程結合之後,完整版的程式碼如下所示


from langchain_community.chat_models.openai import ChatOpenAI
from langchain_community.document_loaders.text import TextLoader
from langchain_core.output_parsers import JsonOutputParser, StrOutputParser
from langchain_core.prompts import PromptTemplate
from langchain_core.runnables import RunnablePassthrough
from utils.langchain_debug import langchain_debug

langchain_debug()
llm = ChatOpenAI()


def get_by_filename(filename):
    info = TextLoader(f'./data/{filename}')
    return info.load()


def get_case_data(_):
    template = """
        你是一個自動化測試工程師,你非常熟悉requests庫
        {context}
        Question: {input}
        請根據傳入的介面資訊提取request中的 ip 、 url 、method、json。
        key值為前面提到的欄位,如果沒有則無需新增。如果有則提取對應的value。
        要求返回的格式為json格式
        """
    prompt = PromptTemplate.from_template(template=template, )
    data_chain = (
            RunnablePassthrough.assign(context=lambda x: get_by_filename("ip.har"), )
            | prompt
            | llm
            | JsonOutputParser()
    )
    return data_chain


def get_case():
    """
    透過大模型生成測試資料。
    :return:
    """
    template = """
        你是一個自動化測試工程師,精通的技術棧為 Python pytest requests庫
        以下是這個介面的具體資訊,你的

        {context}

        請求的引數資訊將輸入一個字典,輸入的內容為
        {req}

        Question: {input}"""
    # 模板提示,輸出 json 格式的回答
    prompt = PromptTemplate.from_template(
        template=template, )
    chain = (
            RunnablePassthrough.
            assign(context=lambda x: get_by_filename("獲取ip測試用例.md"),
                   req=get_case_data)
            | prompt
            | llm
            | StrOutputParser()
    )

    input_template = """
    根據每條測試用例的測試步驟,生成對應的測試資料資訊,
    每條測試用例要求都有一條對應的單獨的pytest函式
    """
    print(chain.invoke({"input": input_template}))


if __name__ == '__main__':
    get_case()

總結

  1. 掌握介面自動化測試用例生成的原理。
  2. 瞭解如何透過大語言模型生成介面自動化測試指令碼與資料。
  3. 掌握透過LangChain生成完整版介面自動化測試用例的方法。

相關文章