测试资料里出现了一个方法名,并不表示替身对象已经核对过这个方法。Python 3.14.8的unittest.mock文档说明,普通Mock在属性被访问时会创建新的子mock,再次访问同一个属性则返回同一个mock;它还能记录自身怎样被使用。这种灵活性意味着,属性能够出现,与属性确实属于原对象,是两个不同问题。[1]
规格约束从spec开始。它可以是一组属性名称,也可以是用作规格的类或实例;采用原对象时,文档说明会据其可见属性形成名称列表。访问列表中不存在的属性,会产生AttributeError。这里约束的是这个mock本身,不能直接把根对象已有规格理解成下面每一个子对象也都获得了对应约束。[1]
Autospeccing继续处理下一层。官方将它描述为递归、惰性实现的规格:沿着mock访问属性时,子属性的接口也对应原规格对象的相应属性。惰性指规格随属性访问而建立,不是预先把整条深层对象链都复制成真实对象。对测试说明的阅读用途,因而是确认名称限制究竟止于根对象,还是继续对应到所访问的子属性。[1]
调用签名是另一项具体限制。被模拟的函数或方法具有与原对象相同的调用签名,错误调用会产生TypeError。create_autospec用于类时复制构造方法的签名,用于可调用对象时复制其调用方法的签名。名称属于接口、参数符合签名,分别回答了“有没有这一项”和“这一项接受怎样的调用”两个问题,不能用一个模糊的“已经模拟”合并表达。[1]
类与实例也要分开读。以类作为规格时,mock的返回值,即所模拟的实例,也具有相同规格;原实例不可调用时,对应的实例mock也不可调用。但文档注释明确说,调用被mock的类来产生mock实例,并没有创建原类的真实实例。因而,这个返回对象的接口依据,不能被写成真实构造过程已经发生的记录。[1]
这正与动态属性的局限相接。官方指出,实例属性常在初始化方法中创建,类本身却没有这些属性;autospec不知道这类动态创建的成员,只把接口限制在可见属性内。某个成员在真实实例中存在,与它在作为规格的类上可见,并不是同一条件。说明规格来源时保留类或实例身份,才能解释为何读者预期的成员没有出现在模拟接口中。[1]
读取与设置还有区别。文档说明,普通autospec禁止取得规格中不存在的属性,并不因此自动禁止后来设置这种属性;更严格的spec_set同时限制取得和设置,不在规格中的名称都会触发AttributeError。这里讨论两种限制的定义,不给出补属性或修改生产类的步骤。[1]
值为None的成员又是一个例外。文档认为None不能提供有用的成员规格,所以autospec不会将它用作该成员的规格,这些成员仍成为普通mock。递归约束因此不等于每个分支都具有完整限制;原成员的值是否能提供规格,仍影响这一分支的表达。[1]
识别可见属性需要自省,即访问原对象的属性。若属性或描述符会触发代码,官方将其列为autospec的适用局限。本文只整理上述接口、签名与可见性关系,没有执行测试或据模拟对象判断生产行为。采用页的版本为3.14.8,页尾更新时间不作为首次发表日期。
信息来源
本文基于上述公开资料整理,未使用来源页面的图片、视频或嵌入媒体。