¥
立即购买

单元测试覆盖

448 浏览
44 试用
11 购买
Nov 24, 2025更新

为指定函数生成全面的单元测试,包括边界情况和错误处理,确保测试覆盖完整,支持CI/CD流程中的代码质量保障与持续集成效果提升。

# pytest unit tests for slugify(title: str) -> str
# Replace 'your_module' below with the actual module name where slugify is defined.
import pytest
from your_module import slugify


# 异常处理:类型校验(非字符串应抛出 TypeError)
@pytest.mark.parametrize("bad_input", [None, 123, 3.14, ["a"], {"t": "x"}, b"bytes"])
def test_slugify_type_error_on_non_string(bad_input):
    with pytest.raises(TypeError):
        slugify(bad_input)


# 文档示例校验(确保示例结果一致)
@pytest.mark.parametrize(
    "title, expected",
    [
        ("  Café déjà vu!  ", "cafe-deja-vu"),
        ("版本2.0 发布", "2-0"),
    ],
)
def test_slugify_doc_examples(title, expected):
    assert slugify(title) == expected


# 核心逻辑:去除重音与变音符,转换为 ASCII 并小写
@pytest.mark.parametrize(
    "title, expected",
    [
        ("Über Façade Coöperate", "uber-facade-cooperate"),  # ü, ç, ö
        ("mañana", "manana"),  # ñ
        ("Crème brûlée", "creme-brulee"),  # è, û, é
        ("straße", "strae"),  # ß 无 ASCII 映射,按实现被忽略
    ],
)
def test_slugify_diacritics_removed_and_lowercased(title, expected):
    assert slugify(title) == expected


# 核心逻辑:非字母数字序列替换为单个连字符,并折叠重复连字符
@pytest.mark.parametrize(
    "title, expected",
    [
        ("Hello---World!!!___", "hello-world"),
        ("a---b--c", "a-b-c"),
        ("foo_bar__baz", "foo-bar-baz"),
        ("Don’t stop!!!", "dont-stop"),  # 弯引号被移除,其余标点合并为单个连字符
        ("Don't Stop", "don-t-stop"),  # 直引号 -> 连字符
    ],
)
def test_slugify_non_alnum_replacement_and_hyphen_collapse(title, expected):
    assert slugify(title) == expected


# 边界条件:去除首尾连字符与空白
@pytest.mark.parametrize(
    "title, expected",
    [
        ("  --Hello--  ", "hello"),
        ("----Title----", "title"),
        ("   A   ", "a"),
    ],
)
def test_slugify_strip_edges(title, expected):
    assert slugify(title) == expected


# 边界条件:当归一化后不剩字母数字时应返回空字符串
@pytest.mark.parametrize(
    "title",
    [
        "",
        "!!!",
        "————",            # 全为非 ASCII 标点
        "版本",             # 非 ASCII 且无数字
        "😀😅🔥",           # emoji
        "--__--",          # 仅分隔符
    ],
)
def test_slugify_returns_empty_when_no_alnum_remains(title):
    assert slugify(title) == ""


# 数字保留与标点处理
@pytest.mark.parametrize(
    "title, expected",
    [
        ("123 Go", "123-go"),
        ("Release 2.0.1-beta", "release-2-0-1-beta"),
        ("v1.2.3", "v1-2-3"),
        ("版本2.0 发布", "2-0"),
    ],
)
def test_slugify_numbers_preserved_and_punctuation_to_hyphen(title, expected):
    assert slugify(title) == expected


# 已是 slug 的字符串应保持(除小写化与规范化外无额外改变)
@pytest.mark.parametrize(
    "title, expected",
    [
        ("some-slug", "some-slug"),
        ("Some-Slug", "some-slug"),
        ("clean-slug-123", "clean-slug-123"),
    ],
)
def test_slugify_already_slug_preserved(title, expected):
    assert slugify(title) == expected


# 非 ASCII 空白(如不间断空格、全角空格)在 ASCII 归一化环节会被移除而非替换为连字符
@pytest.mark.parametrize(
    "title, expected",
    [
        ("A\u00A0B", "ab"),    # 不间断空格被丢弃 -> 无连字符
        ("HELLO 123", "hello123"),  # 全角空格被丢弃;全角字母数字归一化
    ],
)
def test_slugify_non_ascii_whitespace_removed(title, expected):
    assert slugify(title) == expected


# 全角/兼容字符数字与字母的归一化
@pytest.mark.parametrize(
    "title, expected",
    [
        ("HELLO 123", "hello-123"),  # ASCII 空格 -> 连字符;全角数字 -> ASCII 数字
        ("𝟙𝟚3", "123"),              # 数学双线体与全角数字归一化为 ASCII 数字
    ],
)
def test_slugify_fullwidth_and_compat_digits(title, expected):
    assert slugify(title) == expected


# 行分隔与制表符等 ASCII 空白按规则替换为单个连字符
@pytest.mark.parametrize(
    "title, expected",
    [
        ("line1\nline2\tline3", "line1-line2-line3"),
        ("multi \r space", "multi-space"),
    ],
)
def test_slugify_ascii_whitespace_to_hyphen(title, expected):
    assert slugify(title) == expected
package text;

import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.*;

/**
 * Unit tests for TextUtils.truncateWithEllipsis using JUnit Jupiter.
 * Covers: null handling, invalid maxChars, no-truncation paths, wordBoundary behavior,
 * and trimming of trailing whitespace across different whitespace characters and Unicode.
 */
public class TextUtilsTest {

    // === Boundary & Exception Handling ===

    // Null input should return null, regardless of wordBoundary flag.
    @Test
    void nullInputReturnsNull() {
        assertNull(TextUtils.truncateWithEllipsis(null, 5, false));
        assertNull(TextUtils.truncateWithEllipsis(null, 5, true));
    }

    // maxChars < 1 should throw IllegalArgumentException.
    @Test
    void maxCharsLessThanOneThrows() {
        assertThrows(IllegalArgumentException.class,
                () -> TextUtils.truncateWithEllipsis("abc", 0, false));
        assertThrows(IllegalArgumentException.class,
                () -> TextUtils.truncateWithEllipsis("abc", -1, true));
    }

    // === No Truncation Paths (text length <= maxChars) ===

    // Returns original text unchanged when length <= maxChars.
    @Test
    void returnsOriginalWhenLengthEqualOrLess() {
        assertEquals("Hello", TextUtils.truncateWithEllipsis("Hello", 5, true));
        assertEquals("短句", TextUtils.truncateWithEllipsis("短句", 10, true));
        // Trailing spaces should be preserved when not truncated.
        assertEquals("Hi  ", TextUtils.truncateWithEllipsis("Hi  ", 10, false));
        // Only spaces, not truncated.
        assertEquals("   ", TextUtils.truncateWithEllipsis("   ", 5, true));
    }

    // === Truncation without wordBoundary ===

    // Exact cut at maxChars and append ellipsis.
    @Test
    void truncateWithoutWordBoundaryExactCut() {
        assertEquals("Hello...", TextUtils.truncateWithEllipsis("Hello world", 5, false));
        assertEquals("ab...", TextUtils.truncateWithEllipsis("abc", 2, false));
        assertEquals("短句...", TextUtils.truncateWithEllipsis("短句测试", 2, false));
    }

    // Trailing spaces at the cut are removed before ellipsis.
    @Test
    void truncateWithoutWordBoundaryTrailingSpacesTrimmed() {
        // Cut yields trailing space, which should be trimmed.
        assertEquals("Hello...", TextUtils.truncateWithEllipsis("Hello world", 6, false));
        // Multiple spaces trimmed.
        assertEquals("Hello...", TextUtils.truncateWithEllipsis("Hello   world", 8, false));
        // Tab at the cut should be trimmed.
        assertEquals("Hello...", TextUtils.truncateWithEllipsis("Hello\tworld", 6, false));
        // Newline at the cut should be trimmed.
        assertEquals("Hello...", TextUtils.truncateWithEllipsis("Hello\nworld", 6, false));
        // If the cut is a space-only segment, trimmed to empty then ellipsis.
        assertEquals("...", TextUtils.truncateWithEllipsis(" a", 1, false));
        assertEquals("...", TextUtils.truncateWithEllipsis("   b", 2, false));
    }

    // === Truncation with wordBoundary ===

    // Cut at last whitespace within limit; whitespace itself is excluded from substring.
    @Test
    void wordBoundaryCutsAtLastWhitespaceWithinLimit() {
        assertEquals("Hello...", TextUtils.truncateWithEllipsis("Hello world", 7, true));
        assertEquals("Hello world...", TextUtils.truncateWithEllipsis("Hello world again", 12, true));
        // Multiple spaces: should still cut before the last space within limit and trim remaining trailing spaces.
        assertEquals("Hello...", TextUtils.truncateWithEllipsis("Hello   world", 8, true));
    }

    // Whitespace exactly at index 0 should not be used as a cut point (idx > 0 requirement).
    @Test
    void wordBoundaryDoesNotCutWhenWhitespaceIndexIsZero() {
        assertEquals("...", TextUtils.truncateWithEllipsis(" hello", 1, true)); // cut=1, substring is " ", trimmed to empty
    }

    // No whitespace within or at the cut window -> fall back to hard cut at maxChars.
    @Test
    void wordBoundaryFallsBackWhenNoWhitespaceWithinLimit() {
        assertEquals("Super...", TextUtils.truncateWithEllipsis("Supercalifragilistic", 5, true));
    }

    // Whitespace exactly at position == maxChars is ignored by lastWhitespaceBefore (since it scans up to limit-1).
    @Test
    void wordBoundaryIgnoresWhitespaceExactlyAtLimit() {
        // "HelloWorld" (10 chars) then a space at index 10; limit=10, space at limit is ignored.
        assertEquals("HelloWorld...", TextUtils.truncateWithEllipsis("HelloWorld test", 10, true));
    }

    // === Mixed whitespace trimming checks ===

    // Space at cut: trimmed
    @Test
    void trimsSpaceAtCut() {
        assertEquals("Hello...", TextUtils.truncateWithEllipsis("Hello world", 6, true));
    }

    // Newline and tab at cut: trimmed
    @Test
    void trimsNewlineAndTabAtCut() {
        assertEquals("Hello...", TextUtils.truncateWithEllipsis("Hello\nworld", 6, true));
        assertEquals("Hello...", TextUtils.truncateWithEllipsis("Hello\tworld", 6, true));
    }
}
'use strict';
const assert = require('assert');

/**
 * Function under test
 */
/**
 * Simple template rendering: replaces {{key}} with values from data.
 * Features:
 * - Supports default values: {{key|default text}}.
 * - If options.strict is true, throws if a placeholder has no provided value.
 * - Non-string values are coerced with String().
 * - tpl must be a string; throws TypeError otherwise.
 */
function renderTemplate(tpl, data, options) {
  if (typeof tpl !== 'string') {
    throw new TypeError('tpl must be a string');
  }
  const opts = Object.assign({ strict: false }, options || {});
  const ctx = data || {};
  return tpl.replace(/{{\s*([a-zA-Z0-9_.-]+)(?:\|([^}]+))?\s*}}/g, (m, key, def) => {
    const val = getByPath(ctx, key);
    if (val == null) {
      if (opts.strict && def == null) {
        throw new Error('Missing value for ' + key);
      }
      return def != null ? String(def) : (opts.strict ? '' : m);
    }
    return String(val);
  });
}

function getByPath(obj, path) {
  const parts = path.split('.');
  let cur = obj;
  for (const p of parts) {
    if (cur == null || typeof cur !== 'object' || !(p in cur)) {
      return undefined;
    }
    cur = cur[p];
  }
  return cur;
}

describe('renderTemplate', () => {
  // Type enforcement: tpl must be a string
  describe('type checks', () => {
    it('throws TypeError when tpl is not a string', () => {
      const invalids = [null, undefined, 123, {}, [], () => {}];
      for (const v of invalids) {
        assert.throws(() => renderTemplate(v, {}), TypeError);
      }
    });

    it('returns tpl unchanged when there are no placeholders', () => {
      const s = 'Hello world';
      assert.strictEqual(renderTemplate(s, {}), s);
    });
  });

  // Core replacement logic
  describe('basic replacement', () => {
    it('replaces a single placeholder with provided value', () => {
      const out = renderTemplate('Hello {{name}}', { name: 'Ada' });
      assert.strictEqual(out, 'Hello Ada');
    });

    it('replaces multiple occurrences of the same key', () => {
      const out = renderTemplate('X {{name}} {{name}} Y', { name: 'Bob' });
      assert.strictEqual(out, 'X Bob Bob Y');
    });

    it('supports whitespace around key inside placeholder', () => {
      const out = renderTemplate('Hi {{   user.name   }}!', { user: { name: 'Ada' } });
      assert.strictEqual(out, 'Hi Ada!');
    });
  });

  // Non-string value coercion
  describe('value coercion with String()', () => {
    it('coerces numbers', () => {
      const out = renderTemplate('Value: {{n}}', { n: 42 });
      assert.strictEqual(out, 'Value: 42');
    });

    it('coerces booleans', () => {
      const outTrue = renderTemplate('Flag: {{f}}', { f: true });
      const outFalse = renderTemplate('Flag: {{f}}', { f: false });
      assert.strictEqual(outTrue, 'Flag: true');
      assert.strictEqual(outFalse, 'Flag: false');
    });

    it('coerces objects', () => {
      const out = renderTemplate('Obj: {{o}}', { o: { a: 1 } });
      assert.strictEqual(out, 'Obj: [object Object]');
    });

    it('coerces Date via String()', () => {
      const d = new Date('2020-01-01T00:00:00Z');
      const out = renderTemplate('Date: {{d}}', { d });
      assert.strictEqual(out, `Date: ${String(d)}`);
    });
  });

  // Default values behavior
  describe('default values', () => {
    it('uses default when key is missing and strict is false (default)', () => {
      const out = renderTemplate('Hello {{name|friend}}', {});
      assert.strictEqual(out, 'Hello friend');
    });

    it('uses default when value is null', () => {
      const out = renderTemplate('Hello {{name|friend}}', { name: null });
      assert.strictEqual(out, 'Hello friend');
    });

    it('uses default when value is undefined', () => {
      const out = renderTemplate('Hello {{name|friend}}', { });
      assert.strictEqual(out, 'Hello friend');
    });

    it('preserves spaces inside default text', () => {
      const out = renderTemplate('Hello {{name|  friend  }}', {});
      assert.strictEqual(out, 'Hello   friend  ');
    });

    it('supports default text containing the pipe character', () => {
      const out = renderTemplate('Hello {{name|foo|bar}}', {});
      assert.strictEqual(out, 'Hello foo|bar');
    });

    it('supports empty default string', () => {
      const out = renderTemplate('X{{missing|}}Y', {});
      assert.strictEqual(out, 'XY');
    });
  });

  // Strict mode behavior
  describe('strict mode', () => {
    it('throws when missing value and no default', () => {
      assert.throws(
        () => renderTemplate('Hello {{name}}', {}, { strict: true }),
        (err) => err instanceof Error && /Missing value for name/.test(err.message)
      );
    });

    it('does not throw when default is provided', () => {
      const out = renderTemplate('Hello {{name|friend}}', {}, { strict: true });
      assert.strictEqual(out, 'Hello friend');
    });

    it('throws when nested value is missing and no default', () => {
      assert.throws(
        () => renderTemplate('Hi {{user.name}}', { user: {} }, { strict: true }),
        (err) => err instanceof Error && /Missing value for user\.name/.test(err.message)
      );
    });
  });

  // Path resolution with getByPath
  describe('path resolution and key formats', () => {
    it('supports nested paths with dots', () => {
      const out = renderTemplate('Hello {{user.name}}', { user: { name: 'Ada' } });
      assert.strictEqual(out, 'Hello Ada');
    });

    it('falls back to default when intermediate path is not an object', () => {
      const out = renderTemplate('Hello {{user.name|friend}}', { user: 'string' });
      assert.strictEqual(out, 'Hello friend');
    });

    it('supports keys with hyphens', () => {
      const out = renderTemplate('Hi {{user-name}}', { 'user-name': 'Bob' });
      assert.strictEqual(out, 'Hi Bob');
    });

    it('supports keys with underscores and numbers', () => {
      const out = renderTemplate('ID: {{user_1}}', { user_1: 7 });
      assert.strictEqual(out, 'ID: 7');
    });

    it('supports array index in path', () => {
      const out = renderTemplate('Item: {{items.0.name}}', { items: [{ name: 'A' }, { name: 'B' }] });
      assert.strictEqual(out, 'Item: A');
    });

    it('array path falls back to default when index missing', () => {
      const out = renderTemplate('Item: {{items.2.name|X}}', { items: [{ name: 'A' }, { name: 'B' }] });
      assert.strictEqual(out, 'Item: X');
    });
  });

  // Missing values behavior when not strict
  describe('missing values when not strict', () => {
    it('leaves placeholder unchanged when key missing and no default (strict=false)', () => {
      const out = renderTemplate('Hi {{who}}', {}, { strict: false });
      assert.strictEqual(out, 'Hi {{who}}');
    });

    it('leaves placeholder unchanged with data as non-object and no default', () => {
      const out = renderTemplate('Val: {{toString}}', 42, { strict: false });
      assert.strictEqual(out, 'Val: {{toString}}');
    });
  });

  // Handling null/undefined distinctly from false/0
  describe('null/undefined vs falsy non-null', () => {
    it('treats 0 as a valid value', () => {
      const out = renderTemplate('Zero: {{n}}', { n: 0 });
      assert.strictEqual(out, 'Zero: 0');
    });

    it('treats false as a valid value', () => {
      const out = renderTemplate('Bool: {{b}}', { b: false });
      assert.strictEqual(out, 'Bool: false');
    });

    it('treats undefined as missing (uses default)', () => {
      const out = renderTemplate('Undef: {{x|def}}', { });
      assert.strictEqual(out, 'Undef: def');
    });

    it('treats null as missing (uses default)', () => {
      const out = renderTemplate('Null: {{x|def}}', { x: null });
      assert.strictEqual(out, 'Null: def');
    });
  });

  // Multiple placeholders with mixed cases
  describe('multiple placeholders mixed cases', () => {
    it('replaces present values and applies defaults for missing', () => {
      const out = renderTemplate('Hi {{first}} {{last|Doe}}!', { first: 'John' });
      assert.strictEqual(out, 'Hi John Doe!');
    });

    it('throws on any missing without default in strict mode even if others have values', () => {
      assert.throws(
        () => renderTemplate('A {{ok}} B {{missing}}', { ok: 'K' }, { strict: true }),
        (err) => err instanceof Error && /Missing value for missing/.test(err.message)
      );
    });
  });
});

示例详情

解决的问题

帮助开发者快速生成全面、高质量、覆盖边界情况与错误处理的单元测试,从而提高代码可靠性和开发效率。

适用用户

后端开发工程师

通过提示词快速生成复杂后台逻辑的单元测试代码,节省时间并提升项目代码质量。

测试开发人员

高效覆盖潜在边界和错误场景,协助团队发现bug并优化测试流程。

创业公司技术团队

快速生成标准化测试案例模板,减少人工检查测试覆盖率的时间成本。

特征总结

轻松生成全面单元测试代码,覆盖边界情况和多种处理场景,提升测试可靠性。
智能关注错误处理,通过自动检测和生成测试用例减少潜在程序漏洞。
快速覆盖复杂业务逻辑,提升代码质量的同时节省开发时间。
支持多种编程语言和测试框架,满足不同开发团队的技术需求。
一键创建标准化测试模板,降低团队中手工编写测试的难度与成本。
自动优化测试覆盖范围,让复杂代码逻辑的测试更加无缝精准。
灵活调用提示词模板,轻松实现测试场景扩展,适应多样化项目需求。
贴合实际开发场景,提供更专业的测试建议,帮助团队轻松应对版本迭代。

如何使用购买的提示词模板

1. 直接在外部 Chat 应用中使用

将模板生成的提示词复制粘贴到您常用的 Chat 应用(如 ChatGPT、Claude 等),即可直接对话使用,无需额外开发。适合个人快速体验和轻量使用场景。

2. 发布为 API 接口调用

把提示词模板转化为 API,您的程序可任意修改模板参数,通过接口直接调用,轻松实现自动化与批量处理。适合开发者集成与业务系统嵌入。

3. 在 MCP Client 中配置使用

在 MCP client 中配置对应的 server 地址,让您的 AI 应用自动调用提示词模板。适合高级用户和团队协作,让提示词在不同 AI 工具间无缝衔接。

AI 提示词价格
¥25.00元
先用后买,用好了再付款,超安全!

您购买后可以获得什么

获得完整提示词模板
- 共 501 tokens
- 3 个可调节参数
{ 编程语言 } { 测试框架 } { 目标函数代码 }
获得社区贡献内容的使用权
- 精选社区优质案例,助您快速上手提示词
使用提示词兑换券,低至 ¥ 9.9
了解兑换券 →
限时半价

不要错过!

半价获取高级提示词-优惠即将到期

17
:
23
小时
:
59
分钟
:
59