使用 ChatGPT 编写不可破解的代码!

290 阅读4分钟

如果你作为一个程序员还没有使用ChatGPT,那你就错过了!我将向你展示我最喜欢的一个使用ChatGPT的技巧!

我将向你展示我最喜欢的一个使用ChatGPT的小技巧:使用ChatGPT来编写基于属性的测试!

基于属性的测试,A.K.A PBTs,允许你只用一个PBT就能运行数百个单元测试。它通过让你定义一个函数的属性,然后用你的全部输入来运行它,如果你的函数没有通过测试,PBT将找到会使该函数失败的最小值。

从理论上讲,如果你能够测试一个函数的所有属性,那么你的函数现在是不可破译的!这是因为你的函数的属性是不可能的!这是因为你的函数的属性就是你的函数的定义:如果你的定义是完美的,那么这个函数就是完美的!这就是你的函数的定义!

Oooookay,所以我认为这有点令人困惑,所以让我给你看一个例子来代替!

假设我们有一个加法函数:

def add(a, b):
  return a + b

进入全屏模式 退出全屏模式

我们通常的测试方法是做这样的事情:

def test_add_1(a, b):
  assert add(1, 1) = 2

进入全屏模式 退出全屏模式

但是如果一个奇怪的开发者用这个实现来代替呢?

def add(a, b):
  return 2

进入全屏模式 退出全屏模式

很明显,这将通过测试,但在其他情况下会失败。

这就是单元测试失败的原因。你不可能为每一个可能的输入手动编写所有可能的测试。对于基于属性的测试,你可以通过测试函数属性本身来实现这一点。

你可以做的是用基于属性的测试来测试这些属性。

加法的属性之一是identity 属性。无论你把什么数字加到0,它都会返回这个数字。

为了测试这一点,我们可以做这样的事情:

@given(st.floats())
def test_add_identity(a)
  assert add(a, 0) == a

进入全屏模式 退出全屏模式


这样做的目的是,对于所有的浮点数,它将测试把这个数加到0是否会一直返回自己。在这个奇怪的实现中,如果a是2,那么它就能工作,但随后PBT会继续测试其他的值,直到它遇到问题。

现在这显然仍有漏洞,但如果你设法测试所有的属性,如交换、关联等,那么你将有一个牢不可破的函数。


现在我们明白了这些测试是多么强大。让我们用ChatGPT来做一个更复杂的例子!

让我们用这个天真的Pearson r实现:

def pearson_correlation_coefficient(x_values, y_values):
    x_mean = sum(x_values) / len(x_values)
    y_mean = sum(y_values) / len(y_values)

    covariance = sum((x - x_mean) * (y - y_mean) for x, y in zip(x_values, y_values)) / len(x_values)
    stddev_x = (sum((x - x_mean) ** 2 for x in x_values) / len(x_values)) ** 0.5
    stddev_y = (sum((y - y_mean) ** 2 for y in y_values) / len(y_values)) ** 0.5

    return covariance / (stddev_x * stddev_y)

进入全屏模式 退出全屏模式

这有明显的bug,但假设你暂时不知道。
要为这些写基于属性的测试,我们可以做使用这个ChatGPT提示:

为以下代码创建基于属性的测试。请全面测试所有的属性和情况,特别是那些会使函数失败的情况。请确保使用文档字符串彻底记录被测试的属性。使用library 作为测试库。

代码:
insert code

与我们的函数一起,完整的提示将看起来像这样:
Complete prompt for Pearson r example

这个提示为我生成了这些基于属性的测试:

import pytest
from hypothesis import given, strategies as st

@pytest.fixture()
def pearson_corr():
    return pearson_correlation_coefficient

@given(st.lists(st.floats()), st.lists(st.floats()))
def test_pearson_correlation_coefficient_valid_input(pearson_corr, x_values, y_values):
    """
    Test the pearson_correlation_coefficient function with valid input.
    It should return a value between -1 and 1, inclusive.
    """
    if len(x_values) < 2 or len(y_values) < 2:
        with pytest.raises(ZeroDivisionError):
            pearson_corr(x_values, y_values)
    else:
        result = pearson_corr(x_values, y_values)
        assert -1 <= result <= 1

@given(st.lists(st.floats(min_value=-100, max_value=100), min_size=2), st.lists(st.floats(min_value=-100, max_value=100), min_size=2))
def test_pearson_correlation_coefficient_identical_inputs(pearson_corr, x_values, y_values):
    """
    Test the pearson_correlation_coefficient function with identical inputs.
    It should return 1.
    """
    result = pearson_corr(x_values, x_values)
    assert result == 1

@given(st.lists(st.floats(min_value=-100, max_value=100), min_size=2), st.lists(st.floats(min_value=-100, max_value=100), min_size=2))
def test_pearson_correlation_coefficient_negative_identical_inputs(pearson_corr, x_values, y_values):
    """
    Test the pearson_correlation_coefficient function with identical inputs but with one list negated.
    It should return -1.
    """
    y_values_neg = [-y for y in y_values]
    result = pearson_corr(x_values, y_values_neg)
    assert result == -1

@given(st.lists(st.floats(min_value=-100, max_value=100), min_size=2), st.lists(st.floats(min_value=-100, max_value=100), min_size=2))
def test_pearson_correlation_coefficient_orthogonal_inputs(pearson_corr, x_values, y_values):
    """
    Test the pearson_correlation_coefficient function with orthogonal inputs.
    It should return 0.
    """
    x_values_orth = [y for y in y_values]
    result = pearson_corr(x_values, x_values_orth)
    assert result == 0

@given(st.lists(st.floats(), min_size=1), st.lists(st.floats(), min_size=1))
def test_pearson_correlation_coefficient_zero_division_error(pearson_corr, x_values, y_values):
    """
    Test the pearson_correlation_coefficient function with inputs that have zero variance.
    It should raise a ZeroDivisionError.
    """
    with pytest.raises(ZeroDivisionError):
        pearson_corr(x_values, y_values)

@given(st.lists(st.floats()), st.lists(st.floats()))
def test_pearson_correlation_coefficient_same_length(pearson_corr, x_values, y_values):
    """
    Test the pearson_correlation_coefficient function with inputs that have different lengths.
    It should raise a ValueError.
    """
    x_values.pop()
    with pytest.raises(ValueError):
        pearson_corr(x_values, y_values)

正如你所看到的,使用ChatGPT,生成测试是非常容易的,它可以防止你的代码出现错误。在我作为一个数据工程师的工作中,我几乎每天都在使用它。现在,用你自己的代码试试吧,准备好大吃一惊吧!