You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用Hypothesis生成含重复字符的字符串优化游程编码往返测试?

优化Hypothesis往返测试策略:自定义Run-Length编码/解码函数

问题背景

需要对自定义的Run-Length编码/解码函数做往返测试(decode(encode(s)) == s 或 encode(decode(l)) == l),但当前用st.text()生成的测试字符串重复字符占比低,无法充分验证编码/解码逻辑的正确性,需要优化Hypothesis生成策略,用one_of生成含随机位置、随机长度重复字符的字符串,或直接生成符合编码格式的列表。

原实现代码

from hypothesis import given, strategies as st
from itertools import groupby
from typing import List, Union

def run_length_encoder(in_string: str) -> List[Union[str, int]]:
    """
    >>> run_length_encoder("aaaaabbcbc")
    ['a', 'a', 5, 'b', 'b', 2, 'c', 'b', 'c']
    """
    assert isinstance(in_string, str)
    out = []
    for item, group in groupby(in_string):
        cnt = sum(1 for x in group)
        if cnt == 1:
            out.append(item)
        else:
            out.extend((item, item, cnt))
    assert isinstance(out, list)
    assert all(isinstance(x, (str, int)) for x in out)
    return out

def run_length_decoder(in_list: List[Union[str, int]]) -> str:
    """
    >>> run_length_decoder(['a', 'a', 5, 'b', 'b', 2, 'c', 'b', 'c'])
    "aaaaabbcbc"
    """
    assert isinstance(in_list, list)
    assert all(isinstance(x, (str, int)) for x in in_list)
    out: str = ""
    for item in in_list:
        if isinstance(item, int):
            out += out[-1] * (item - 2)
        else:
            out += item
    assert isinstance(out, str)
    return out

原测试代码

@given(
    in_string = st.text()
)
def test_roundtrip_run_length_encoder_decoder(in_string):
    encoded_list = run_length_encoder(in_string)
    assert isinstance(encoded_list, list)
    assert all(isinstance(x, (str, int)) for x in encoded_list)
    decoded_string = run_length_decoder(encoded_list)
    assert isinstance(decoded_string, str)
    assert in_string == decoded_string, (in_string, decoded_string)

test_roundtrip_run_length_encoder_decoder()

优化方案

方案1:生成含随机重复字符的字符串

用st.one_of混合基础文本策略和重复字符块策略,确保测试用例包含足够多的重复场景:

# 生成单个字符+重复次数的元组,次数≥1
repeat_block = st.tuples(
    st.characters(),
    st.integers(min_value=1, max_value=20)  # 重复次数可根据需求调整
).map(lambda t: t[0] * t[1])

# 混合基础文本和重复块拼接的文本
text_with_repeats = st.one_of(
    st.text(),  # 保留原有基础文本测试场景
    st.lists(repeat_block, min_size=1).map(''.join)  # 多个重复块拼接成字符串
)

@given(in_string=text_with_repeats)
def test_roundtrip_run_length_encoder_decoder(in_string):
    encoded_list = run_length_encoder(in_string)
    decoded_string = run_length_decoder(encoded_list)
    assert in_string == decoded_string, f"Original: {in_string}, Decoded: {decoded_string}"

方案2:直接生成符合编码格式的列表

针对encode(decode(l)) == l的往返测试,直接构造符合编码规则的列表策略,更精准测试解码后再编码的正确性:

# 生成单个字符项(对应原字符串中出现1次的字符)
single_char_item = st.characters().map(lambda c: [c])

# 生成重复项:[char, char, count],count≥2(对应原字符串中出现≥2次的字符)
repeat_item = st.tuples(
    st.characters(),
    st.integers(min_value=2, max_value=20)
).map(lambda t: [t[0], t[0], t[1]])

# 混合两种项,拼接成符合编码格式的列表
encoded_list_strategy = st.lists(
    st.one_of(single_char_item, repeat_item),
    min_size=0
).map(lambda lst: [item for sublist in lst for item in sublist])

@given(in_list=encoded_list_strategy)
def test_roundtrip_run_length_decoder_encoder(in_list):
    decoded_string = run_length_decoder(in_list)
    encoded_list = run_length_encoder(decoded_string)
    assert in_list == encoded_list, f"Original list: {in_list}, Encoded list: {encoded_list}"

说明

  • 方案1重点覆盖编码→解码的往返逻辑,确保任意字符串经过编码解码后还原;
  • 方案2重点覆盖解码→编码的往返逻辑,确保符合编码格式的列表经过解码编码后还原;
  • 两个方案可结合使用,全面验证函数的正确性。

内容的提问来源于stack exchange,提问作者fabio

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 21:05:07