我用这个 AI 工具生成单元测试,简直不要太爽!

本文分享如何使用驭码CodeRider 的单元测试功能生成单元测试文件。

在之前的文章如何用 Python 手撸一个 GitLab 代码安全审查工具?中,我用 Python 写了一个接受极狐GitLab 代码安全审计事件流并且将消息推送到钉钉群的脚本,完整的 python 代码为:

    from fastapi import FastAPI
    import uvicorn
    import requests
    import json

    app = FastAPI()

    @app.post("/jh-gitlab")
    async def gitlab_payload(data: dict):
        # 抓取审计事件中的主要信息
        audit_event_info = {
            "Action": data['details']['custom_message'],
            "Author": data['details']['author_name'],
            "IP Address": data['details']['ip_address'],
            "Entity Path": data['details']['entity_path'],
            "Target Details": data['target_details']
        }
        print(audit_event_info)

        # 发送消息通知
        notification(audit_event_info)

    def notification(payload: dict):
        webhook_url = "https://oapi.dingtalk.com/robot/send?access_token=你的钉钉 webhook token"

        # 发送消息的内容
        message = {
            "msgtype": "text",
            "text": {
                "content" : "GitLab: {}".format(json.dumps(payload))
            }
        }

        # 发送 POST 请求
        headers = {'Content-Type': 'application/json'}
        response = requests.post(webhook_url, data=json.dumps(message), headers=headers)
        print(response.text)
        if json.loads(response.text)['errcode'] == 0:
            print("Send Message Success!")
            return True
        else:
            print("Send Message Failed!")
            return json.loads(response.text)['errmsg']


    if __name__ == "__main__":
        uvicorn.run(app, host="0.0.0.0", port=8000)

对于这段代码写的是否 OK 最好的验证方法就是生成一些单元测试来测试。为了方便,我决定用 AI 工具来帮我生成单元测试代码。

我选择的是极狐GitLab 公司自研发布的 AI 产品驭码CodeRider(当前该产品可以免费试用【https://dl.gitlab.cn/aeh2irfy】)。 该产品就有一个单元测试生成功能,当我在 PyCharm 中安装好驭码CodeRier 并直接点击test命令时:

file

就开始了单元测试代码的自动生成:

file

最终生成了如下测试代码:

from fastapi.testclient import TestClient
from unittest.mock import patch
import json

from main import app, notification

client = TestClient(app)

def test_gitlab_payload_success():
    payload = {
        "details": {
            "custom_message": "Project marked for deletion",
            "author_name": "Administrator",
            "ip_address": "36.133.246.166",
            "entity_path": "devsecops/ai-deleted-7"
        },
        "target_details": "ai-deleted-7"
    }

    with patch('main.notification') as mock_notification:
        mock_notification.return_value = True
        response = client.post("/jh-gitlab", json=payload)
        assert response.status_code == 200
        mock_notification.assert_called_once_with({
            "Action": "Project marked for deletion",
            "Author": "Administrator",
            "IP Address": "36.133.246.166",
            "Entity Path": "devsecops/ai-deleted-7",
            "Target Details": "ai-deleted-7"
        })

def test_gitlab_payload_missing_fields():
    payload = {
        "details": {
            "custom_message": "Project marked for deletion",
            "author_name": "Administrator",
            "ip_address": "36.133.246.166"
        },
        "target_details": "ai-deleted-7"
    }

    response = client.post("/jh-gitlab", json=payload)
    assert response.status_code == 422

def test_notification_success():
    payload = {
        "Action": "Project marked for deletion",
        "Author": "Administrator",
        "IP Address": "36.133.246.166",
        "Entity Path": "devsecops/ai-deleted-7",
        "Target Details": "ai-deleted-7"
    }

    with patch('requests.post') as mock_post:
        mock_response = mock_post.return_value
        mock_response.text = json.dumps({"errcode": 0, "errmsg": "ok"})
        result = notification(payload)
        assert result == True
        mock_post.assert_called_once()

def test_notification_failure():
    payload = {
        "Action": "Project marked for deletion",
        "Author": "Administrator",
        "IP Address": "36.133.246.166",
        "Entity Path": "devsecops/ai-deleted-7",
        "Target Details": "ai-deleted-7"
    }

    with patch('requests.post') as mock_post:
        mock_response = mock_post.return_value
        mock_response.text = json.dumps({"errcode": 400, "errmsg": "Bad Request"})
        result = notification(payload)
        assert result == "Bad Request"
        mock_post.assert_called_once()

看到这些代码,我就想知道怎么测试呢。然后就问驭码CodeRider,如果要运行这些单元测试,我该怎么操作?

file

驭码CodeRider 给的答案是四步:

  • 第一步安装依赖
  • 第二步将测试代码存放在 test_main.py文件中
  • 第三步运行测试文件
  • 第四步查看答案

我就遵照四步进行了测试,出现了错误:

file

提示 FAILED pytest_main.py::test_gitlab_payload_missing_entity_path - KeyError: 'entity_path'。仔细看了一下,测试代码中有一个检测缺失字段的环节,我代码中的 payload 有五个参数:ActionAuthorIP AddressEntity Path以及 Target Details

下面代码

def test_gitlab_payload_missing_fields():
    payload = {
        "details": {
            "custom_message": "Project marked for deletion",
            "author_name": "Administrator",
            "ip_address": "36.133.246.166"
        },
        "target_details": "ai-deleted-7"
    }

    response = client.post("/jh-gitlab", json=payload)
    assert response.status_code == 422

用来测试在缺失 entity_path字段的情况。比较遗憾的是,我在源代码中并没有对 payload 中的字段进行校验处理。所以我把这个错误发给了驭码CodeRider:

file

驭码CodeRider 给出了两种解决方案:

  • 方案一:在测试中添加 entity_path 字段
  • 方案二:修改 gitlab_payload 函数以处理缺失字段

按照这两种方式都可以,我选择了修改 gitlab_payload相关代码,于是继续问了驭码CodeRider:

file

驭码给的修改代码为:

    audit_event_info = {
        "Action": data['details'].get('custom_message', 'Unknown Action'),
        "Author": data['details'].get('author_name', 'Unknown Author'),
        "IP Address": data['details'].get('ip_address', 'Unknown IP'),
        "Entity Path": data['details'].get('entity_path', 'Unknown Path'),
        "Target Details": data.get('target_details', 'Unknown Target')
    }

就是给缺失的字段增加默认值。接着执行测试命令:

file

可以看到 4 条测试全部通过。

当然,上面的整个流程仅仅为测试使用,生成的单元测试不一定是最准确、最后直接可以使用的,但是我们可以看到用 AI 来生成单元测试文件至少是靠谱的、能够减轻不少工作量,先用 AI 生成,然后做一些修改,这样工作能轻松不少。

用 AI 来帮助生成单元测试文件看来靠谱,驭码CodeRiderhttps://dl.gitlab.cn/aeh2irfy】可以的!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,186评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,858评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,620评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,888评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,009评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,149评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,204评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,956评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,385评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,698评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,863评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,544评论 4 335
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,185评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,899评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,141评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,684评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,750评论 2 351

推荐阅读更多精彩内容