
文档知识库教程OpenHarmony【免费下载链接】CangjieCorpus本仓库为仓颉编程语言语料库聚焦 仓颉编程语言 核心知识体系整合官方开发指南、API 文档、典型代码示例及语法规范等多维度资源经结构化处理与专业标注构建为支持 RAG检索增强生成技术 的高质量知识基座适配智能编码助手、学习辅助工具等应用开发需求。 欢迎开发者基于本语料库构建仓颉语言智能应用推动鸿蒙开发生态智能化升级项目地址https://gitcode.com/Cangjie/CangjieCorpus点击查看免费下载std.unittest.prop_test是仓颉标准库中为单元测试框架std.unittest提供参数化测试底层能力的包模块总览将其概括为为单元测试框架提供了参数化测试所需的类型和一些通用方法。它通过ArbitraryT随机值生成、ShrinkT失败用例数据缩减、RandomSource基础随机数供给三大接口以及Generators、LazySeq、ShrinkHelpers等工具类支撑起仓颉随机参数化测试从数据生成—断言验证—失败缩减—可复现回归的完整闭环。读完本篇你可以掌握如何在仓颉测试中用Test[...] in random()编写随机测试、为自定义类型扩展Arbitrary/Shrink实例并理解框架内部RandomDataStrategy的生成与缩减机制。包结构总览unittest.prop_test包位于语料库 libs/std/unittest_prop_test/ 目录下按 API 类型拆分为四份文档API 类别文档内容函数函数 APIemptyIterableT()、randomT()接口接口 APIArbitraryT、IndexAccess、RandomSource、ShrinkT类类 APIGenerators、LazySeqT、ShrinkHelpers结构体结构体 APIFunction0WrapperR、TupleWrapper2T0,T1~TupleWrapper5T0..T4需要强调的是unittest.prop_test并不是用户日常唯一需要直接导入的包。unittest 包概述中明确列出了从 unittest.prop_test 包中重导出的 API其中randomT()函数、Arbitrary与Shrink接口都被重导出。这意味着在测试代码中只import std.unittest即可直接使用random()、ArbitraryT、ShrinkT这正是 参数化测试示例中Test[array in random()]写法可以直接工作的原因。顶层函数参数源入口random ()public func randomT(): RandomDataStrategyT where T : ArbitraryT该函数是随机参数化测试的统一入口用于生成T类型的随机数据约束条件为T必须实现ArbitraryT接口。其返回值是RandomDataStrategyT——一个参数化测试的参数源即DataStrategyT的一种具体实现定义见 unittest 类 API。从源码结构看RandomDataStrategyT的声明为public class RandomDataStrategyT : DataStrategyT where T : ArbitraryT它通过provider(configuration)返回RandomDataProviderT负责按步骤生成数据通过shrinker(configuration)返回RandomDataShrinkerT负责失败后缩减数据。这正好对应了unittest.common中DataStrategy的三个组件接口DataProvider提供测试数据、DataShrinker缩减数据、DataStrategy组合策略。也就是说random()把随机生成和数据缩减两件事打包成了一个可被Test[...] in ...DSL 直接消费的策略对象。random()在测试宏 DSL 中的典型用法摘自 参数化测试示例Test[ array in random() ] func testRandomArrays(array: ArrayInt64) { // 测试数组是否已排序 for (i in 0..(array.size - 1)) { Expect(array[i] array[i 1]) } }该测试默认生成 200 个随机值用于测试。文档特别说明数值并非完全随机而是偏向于边界值例如特定类型的零、最大值和最小值、空集合等。这与下文Arbitrary的内置实现策略相呼应。emptyIterable ()public func emptyIterableT(): IterableT创建一个空的迭代器返回IteratorT。它常被用作Shrink实现或生成器逻辑的默认/空结果返回表示没有可缩减的值。接口一Arbitrary —— 随机值生成的契约public interface ArbitraryT { static func arbitrary(random: RandomSource): GeneratorT }ArbitraryT是如何生成一个T类型随机值的契约。它只有一个静态方法arbitrary接收一个RandomSource随机数来源返回一个GeneratorT生成器。GeneratorT定义在 unittest 接口 API中接口体仅含func next(): T即每次调用next()产出一个T值。Arbitrary的关键设计是静态方法它不要求类型持有实例状态而是以类型级的方式描述如何生成自己的随机值配合where T : ArbitraryT约束即可被random()和Generators.lookup等泛型入口消费。内置类型的 Arbitrary 实现接口 API列出了Arbitrary为大量内置类型提供的extend ... : Arbitrary...扩展实现可按类型归为四类布尔与文本Bool、Rune、String整型Int8、Int16、Int32、Int64、IntNative、UInt8、UInt16、UInt32、UInt64、UIntNative浮点Float16、Float32、Float64枚举与单元Ordering、Unit泛型容器要求元素类型自身也实现ArbitraryextendT ArrayT : ArbitraryArrayT where T : ArbitraryT extendT OptionT : ArbitraryOptionT where T : ArbitraryT extendT ArrayListT : ArbitraryArrayListT where T : ArbitraryT extendT HashSetT : ArbitraryHashSetT where T : ArbitraryT extendK, V HashMapK, V : ArbitraryHashMapK, V where K : ArbitraryK, V : ArbitraryV容器类型通过组合元素类型的Arbitrary实例来生成自身随机值这正是泛型测试能够随机生成整个集合的基础。为自定义类型扩展 Arbitrary对于用户自定义类型需要手动extend实现Arbitrary。一个典型的组合式实现思路利用Generators工具类把生成各字段组合成生成整个对象见下文Generators.mapped。例如为一个带两个Int64字段的自定义类型Point实现extend Point : ArbitraryPoint { static func arbitrary(random: RandomSource): GeneratorPoint { Generators.mapped(random, { (x: Int64, y: Int64) Point(x, y) }) } }实现后即可在测试中通过Test[p in random()]随机生成Point值。接口二RandomSource —— 基础随机数供给public interface RandomSource { func nextBool(): Bool func nextInt8(): Int8 // ... nextInt16/32/64, nextIntNative, nextUInt8/16/32/64, nextUIntNative func nextFloat16(): Float16 func nextFloat32(): Float32 func nextFloat64(): Float64 func nextGaussianFloat64(mean!: Float64, sigma!: Float64): Float64 func suggestUInt8(): UInt8 // ... suggestUInt16/32/64, suggestUIntNative func suggestInt8(): Int8 // ... suggestInt16/32/64, suggestIntNative func suggestFloat16(): Float16 func suggestFloat32(): Float32 func suggestFloat64(): Float64 func suggestBool(): Bool func suggestRune(): Rune }RandomSource提供Arbitrary实现所需的随机生成基础类型数据的能力。从 接口 API的方法签名看其方法大致分为三组全范围next*系列返回对应类型的伪随机数如nextInt64(): Int64、nextFloat64(): Float64。带上限next*(upper)系列返回范围在[0, upper)内的伪随机数例如nextInt16(upper: Int16): Int16。文档明确标注当upper小于等于 0 时抛出IllegalArgumentException对无符号版本则是等于 0 时抛出。suggest*系列同样返回对应类型的伪随机值语义上与next*对应但作为建议值通道提供给Arbitrary组合逻辑使用。此外还有高斯分布方法public func nextGaussianFloat64(mean!: Float64 0.0, sigma!: Float64 1.0): Float64默认获取均值为0.0、标准差为1.0的高斯分布随机数。文档说明mean为位置参数、sigma为尺度参数且该函数内部调用nextGaussianFloat64Implement因此子类如继承自 random 包的 Random 类覆写nextGaussianFloat64Implement后调用会返回覆写结果。这为自定义分布、自定义随机源留下了扩展点。从源码结构看next/suggest的分离让Arbitrary实现既可以直接取原始随机数也可以取用于偏置/边界值构造的建议值这与随机值偏向边界值的生成策略相吻合。接口三Shrink —— 失败数据的自动缩减public interface ShrinkT { func shrink(): IterableT }ShrinkT将一个T值缩减到多个更小的值shrink()返回一组候选较小值的迭代器。这是随机测试失败可复现、可定位的关键当某个随机输入导致断言失败时框架会不断调用shrink()逐步把输入向更小、更简单的形态收缩最终得到一个最小化的失败用例。参数化测试示例中失败输出的这段信息正是缩减机制的产物REASON: After 5 generation steps and 200 reduction steps: array [0, -1196768422]200 reduction steps 即缩减步骤数框架经过 200 步缩减后把原始失败数组压缩成了[0, -1196768422]这样更易读的形式。Shrink同样为大量内置类型提供了extend实现覆盖 接口 API所列的Bool、各整型Int8~IntNative、UInt8~UIntNative、各浮点Float16~Float64、Rune、String、Unit以及泛型容器ArrayT、OptionT、ArrayListT、HashSetT、HashMapK,V容器缩减不要求元素类型实现Shrink仅要求元素可迭代处理。接口四IndexAccess —— 元组索引访问public interface IndexAccess { func getElementAsAny(index: Int64): ?Any }IndexAccess是一个实用程序接口用于通过索引访问元组元素返回?Any索引不合法时返回None。它主要服务于把元组包装为结构体的TupleWrapperN见下文使元组成员可以统一按Int64索引被访问便于框架在生成/缩减多参数元组时做统一处理。工具类一Generators —— 生成器组合工具箱public class Generators {}Generators是一个纯静态辅助类包含辅助函数的类可帮助开发人员编写自己的生成器。它的静态方法覆盖了组合随机生成器的常见模式完整签名见 类 API方法功能说明generateT(body: () - T): GeneratorT通过重复调用闭包生成值把任意可调用对象包装成生成器iterableT(random, collection: ArrayT): GeneratorT从数组中随机选取在有限候选集中随机取值lookupT(random): GeneratorT where T : ArbitraryT通过T的Arbitrary实例获取生成器是random()背后的核心查找mappedT, R(random, body: (T) - R): GeneratorR取T的生成器并映射为R支持 1~4 个输入参数的重载pickT(random, variants: ArrayGeneratorT): GeneratorT从多个生成器中随机选取一个混合多种生成策略singleT(value: T): GeneratorT始终返回同一个值常量注入weightedT(random, variants: Array(UInt64, GeneratorT)): GeneratorT按权重从 (权重, 生成器) 对中选取控制各分支出现概率mapped提供了 1、2、3、4 个输入参数的四个重载例如双参数版本public static func mappedT1, T2, R(random: RandomSource, body: (T1, T2) - R): GeneratorR where T1 : ArbitraryT1, T2 : ArbitraryT2这让你可以用一行代码把生成两个随机Int64并构造出对象表达为一个生成器是自定义Arbitrary时最常用的工具。weighted则支持用UInt64权重精确控制不同分支的相对出现频率配合偏向边界值的策略实现更精细的数据分布。工具类二LazySeq —— 惰性可记忆序列public class LazySeqT : IterableT { public init() public init(element: T) }LazySeqT是延迟计算的 T 类型值序列用于在迭代时计算和记忆值。文档强调其完全不可变每次操作都会产生一个新的序列因此非常适合表达缩减/生成过程中按需展开、共享片段的序列逻辑。其核心方法见 类 APIappend(element: T): LazySeqT/prepend(element: T): LazySeqT尾/头插入元素返回新序列。concat(other: LazySeqT): LazySeqT拼接序列文档明确复杂度为O(1)。mapU(body: (T) - U): LazySeqU对每个元素做惰性映射。mixWith(other: LazySeqT): LazySeqT及静态mix系列2/3/4/5 个序列把多个序列穿插混合成一个。文档给出直观示例mix({1,2,3,4}, {5,6,7}) - {1,5,2,6,3,7,4}。of(iterable: IterableT)/of(array: ArrayT)从迭代器或数组构造序列。iterator(): IteratorT实现Iterable协议。concat的O(1)与mix的穿插能力使得在缩减过程中可以高效地把候选较小值序列以常数代价拼接、交错而不必立即物化整个序列——这正是延迟计算 记忆语义的价值所在。工具类三ShrinkHelpers —— 元组缩减public class ShrinkHelpers {}ShrinkHelpers提供对元组实现缩减迭代器的方法含 2、3、4、5 元组四个shrinkTuple重载。以二元组为例public static func shrinkTupleT0, T1( tuple: (T0, T1), t0: IterableT0, t1: IterableT1 ): Iterable(T0, T1)它接收被缩减的元组以及每个成员各自的缩减迭代器返回元组级别的缩减迭代器。这让多参数用例失败后如何整体缩减有了统一实现对每个参数分别shrink()再用ShrinkHelpers.shrinkTuple组合成元组的缩减序列框架便可逐维收缩最终输出最小化失败输入。元组封装结构体Function0Wrapper 与 TupleWrapperNunittest.prop_test提供了一组把闭包/元组封装为结构体的类型目的是让生成器/多参数能以一等值形式参与Arbitrary、IndexAccess、Equatable等接口。Function0Wrapperpublic struct Function0WrapperR { public Function0Wrapper(public let function: () - R) }把无参闭包封装为结构体并提供调用操作符operator func () (): R使其可像闭包一样被调用同时还为其扩展了Arbitrary实现where R : ArbitraryR。这允许生成一个函数值参与随机测试。TupleWrapper2T0,T1 ~ TupleWrapper5T0..T4以TupleWrapper2为例public struct TupleWrapper2T0, T1 { public TupleWrapper2(public let tuple: (T0, T1)) }TupleWrapper3、TupleWrapper4、TupleWrapper5结构一致只是封装的元组分别为 3/4/5 元组。每个TupleWrapperN都统一扩展了ToString提供字符串表达EquatableTupleWrapperN...实现与!支持按元组比较判等IndexAccess实现getElementAsAny(index: Int64): ?Any按索引取元组成员不合法索引返回NoneArbitraryTupleWrapperN...要求每个成员类型都实现Arbitrary从而支持随机生成整个元组。applyR(f: (...)-R): R方法则允许对封装的元组应用一个函数。把元组包装成可判等、可按索引访问、可随机生成的结构体是为了让框架在处理多参数用例时能够像处理单一值一样统一地对参数元组做生成、比较、缩减和打印。与 unittest 框架的集成从 random() 到可复现的失败把上面所有部件串起来unittest.prop_test在仓颉单元测试中的完整链路如下声明参数源在Test[...]DSL 中写param in random()。由于unittest重导出了randomT()与Arbitrary无需额外导入prop_test。random()依据参数类型T的ArbitraryT约束构造出RandomDataStrategyT。生成阶段RandomDataStrategy.provider(configuration)产出RandomDataProviderT按generationSteps步反复调用Arbitrary.arbitrary(random)返回的GeneratorT.next()生成输入并执行断言。缩减阶段一旦某次输入导致断言失败shrinker(configuration)产出RandomDataShrinkerT依据T的ShrinkT实现反复调用shrink()把失败输入向更小值收缩对多参数则经ShrinkHelpers.shrinkTuple组合步骤数由reductionSteps控制。可复现回归失败输出中会打印with randomSeed 值把该值写回Configure[randomSeed: 值]即可让同一随机序列稳定复现便于团队共享失败用例。默认generationSteps与reductionSteps的最大值都是 200见 参数化测试示例。完整示例含randomSeed复现、Types泛型参数化、Strategy自定义策略、覆盖率引导随机测试可在该文档中查阅。小结std.unittest.prop_test用三个接口划定了随机参数化测试的职责边界ArbitraryT回答如何随机生成一个值RandomSource回答基础随机数从哪来ShrinkT回答失败后如何把值变小。在此之上Generators提供生成器组合、LazySeq提供惰性可记忆序列、ShrinkHelpers提供元组缩减、TupleWrapperN/Function0Wrapper把多参数与闭包提升为一等值。这些能力经unittest包重导出后最终汇聚为开发者在测试中一行in random()的简洁体验——生成、断言、缩减、复现全部由框架依据Arbitrary/Shrink的实现自动完成。理解这一底层结构就能为任意自定义类型正确扩展随机测试能力并读懂失败报告中generation/reduction steps与randomSeed的确切含义。赞分享文档知识库教程OpenHarmony【免费下载链接】CangjieCorpus本仓库为仓颉编程语言语料库聚焦 仓颉编程语言 核心知识体系整合官方开发指南、API 文档、典型代码示例及语法规范等多维度资源经结构化处理与专业标注构建为支持 RAG检索增强生成技术 的高质量知识基座适配智能编码助手、学习辅助工具等应用开发需求。 欢迎开发者基于本语料库构建仓颉语言智能应用推动鸿蒙开发生态智能化升级项目地址https://gitcode.com/Cangjie/CangjieCorpus点击查看免费下载相关推荐仓颉 std.unittest.prop_test 接口全解Arbitrary、RandomSource、Shrink 与随机属性测试的底层机制仓颉 std.unittest.prop_test 接口全解Arbitrary、RandomSource、Shrink 与随机属性测试的底层机制 本篇聚焦仓颉文档知识库教程OpenHarmony仓颉 std.unittest.prop_test 之 random 与 emptyIterable为参数化测试提供随机数据源的函数详解仓颉 std.unittest.prop_test 之 random 与 emptyIterable为参数化测试提供随机数据源的函数详解 randomT 与文档知识库教程OpenHarmony仓颉 std.unittest.prop_test 属性测试核心类详解Generators、LazySeq 与 ShrinkHelpers仓颉 std.unittest.prop_test 属性测试核心类详解Generators、LazySeq 与 ShrinkHelpers std.unitt文档知识库教程OpenHarmony上一篇告别断流与网卡失灵RTL8852BE 驱动安装到满速调优完整指南下一篇SMUDebugTool从开机报错到顺手调机一份能直接照做的Ryzen调试实战笔记创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考