×
¥
查看详情
🔥 会员专享 文生文 API

单元测试覆盖

👁️ 475 次查看
📅 Nov 24, 2025
💡 核心价值: 为指定函数生成全面的单元测试,包括边界情况和错误处理,确保测试覆盖完整,支持CI/CD流程中的代码质量保障与持续集成效果提升。

🎯 可自定义参数(3个)

编程语言
生成单元测试代码所使用的编程语言
测试框架
生成单元测试代码所使用的测试框架
目标函数代码
需要生成单元测试的函数或代码段

🎨 效果示例

# 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)
      );
    });
  });
});

示例详情

📖 如何使用

30秒出活:复制 → 粘贴 → 搞定
与其花几十分钟和AI聊天、试错,不如直接复制这些经过千人验证的模板,修改几个 {{变量}} 就能立刻获得专业级输出。省下来的时间,足够你轻松享受两杯咖啡!
加载中...
💬 不会填参数?让 AI 反过来问你
不确定变量该填什么?一键转为对话模式,AI 会像资深顾问一样逐步引导你,问几个问题就能自动生成完美匹配你需求的定制结果。零门槛,开口就行。
转为对话模式
🚀 告别复制粘贴,Chat 里直接调用
无需切换,输入 / 唤醒 8000+ 专家级提示词。 插件将全站提示词库深度集成于 Chat 输入框。基于当前对话语境,系统智能推荐最契合的 Prompt 并自动完成参数化,让海量资源触手可及,从此彻底告别"手动搬运"。
即将推出
🔌 接口一调,提示词自己会进化
手动跑一次还行,跑一百次呢?通过 API 接口动态注入变量,接入批量评价引擎,让程序自动迭代出更高质量的提示词方案。Prompt 会自己进化,你只管收结果。
发布 API
🤖 一键变成你的专属 Agent 应用
不想每次都配参数?把这条提示词直接发布成独立 Agent,内嵌图片生成、参数优化等工具,分享链接就能用。给团队或客户一个"开箱即用"的完整方案。
创建 Agent

✅ 特性总结

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

🎯 解决的问题

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

🕒 版本历史

当前版本
v2.1 2024-01-15
优化输出结构,增强情节连贯性
  • ✨ 新增章节节奏控制参数
  • 🔧 优化人物关系描述逻辑
  • 📝 改进主题深化引导语
  • 🎯 增强情节转折点设计
v2.0 2023-12-20
重构提示词架构,提升生成质量
  • 🚀 全新的提示词结构设计
  • 📊 增加输出格式化选项
  • 💡 优化角色塑造引导
v1.5 2023-11-10
修复已知问题,提升稳定性
  • 🐛 修复长文本处理bug
  • ⚡ 提升响应速度
v1.0 2023-10-01
首次发布
  • 🎉 初始版本上线
COMING SOON
版本历史追踪,即将启航
记录每一次提示词的进化与升级,敬请期待。

💬 用户评价

4.8
⭐⭐⭐⭐⭐
基于 28 条评价
5星
85%
4星
12%
3星
3%
👤
电商运营 - 张先生
⭐⭐⭐⭐⭐ 2025-01-15
双十一用这个提示词生成了20多张海报,效果非常好!点击率提升了35%,节省了大量设计时间。参数调整很灵活,能快速适配不同节日。
效果好 节省时间
👤
品牌设计师 - 李女士
⭐⭐⭐⭐⭐ 2025-01-10
作为设计师,这个提示词帮我快速生成创意方向,大大提升了工作效率。生成的海报氛围感很强,稍作调整就能直接使用。
创意好 专业
COMING SOON
用户评价与反馈系统,即将上线
倾听真实反馈,在这里留下您的使用心得,敬请期待。
加载中...