具有属性的 jasmine.createSpyObj

2024-04-12

在我的 Angular 测试中模拟依赖项时,我通常使用以下命令创建一个间谍对象jasmine.createSpyObj:

const serviceSpy= jasmine.createSpyObj('MyService', ['method']);

然后将其提供给 TestBed:

  providers: [
    {provide: MyService, useValue: serviceSpy}
  ]

当我在测试中使用它时,我可以指定所需的返回值:

serviceSpy.method.and.returnValue(of([...]));

现在我还需要模拟属性,但我不知道应该如何完成。createSpyObj确实允许定义属性名称:

const serviceSpy= jasmine.createSpyObj('MyService', ['method'], ['property']);

但我根据大量文章和答案尝试了各种解决方案,但没有成功,例如:

// Cannot read property 'and' of undefined    
serviceSpy.property.and.returnValue(true);  
// not declared configurable
spyOnProperty(serviceSpy, 'property').and.returnValue(true);  
// no build errors, but value stays 'undefined'
serviceSpy.property = true;  

我能让它“一半”工作的唯一方法是:

let fakeValue = true;
const serviceSpy= jasmine.createSpyObj('MyService', ['method'], {'property': fakeValue});

这里的问题是它是在创建时一次性设置的。如果我想改变测试中的期望值,这是行不通的。

fakeValue = false;
serviceSpy.property ==> stays to the initial value 'true';

是否存在通过创建间谍对象来解决模拟方法和属性的解决方案,或者我应该创建自己的假类,然后可以在其上使用spyOn and spyOnProperty?

我还想知道属性数组的用法是什么createSpyObj定义。到目前为止,我还没有在网上看到任何解释它的例子。


Per 文档 https://jasmine.github.io/tutorials/spying_on_properties(强调我的):

您可以通过以下方式快速创建具有多个属性的间谍对象 将属性数组或散列作为第三个参数传递给createSpyObj。在这种情况下,您将不会有对创建的引用 间谍,所以如果您稍后需要改变他们的间谍策略,您将 必须使用Object.getOwnPropertyDescriptor方法.

it("creates a spy object with properties", function() {
  let obj = createSpyObj("myObject", {}, { x: 3, y: 4 });
  expect(obj.x).toEqual(3);

  Object.getOwnPropertyDescriptor(obj, "x").get.and.returnValue(7);
  expect(obj.x).toEqual(7);
});

间谍属性是描述符(参见例如Object.defineProperty on MDN https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty),因此要访问间谍对象,您需要获取描述符对象,然后与get and set其上定义的方法。


在 TypeScript 中,编译器需要一些帮助。createSpyObj https://github.com/DefinitelyTyped/DefinitelyTyped/blob/d063d0175b3eb59a7a4cc5e64992f8a220d9a910/types/jasmine/index.d.ts#L292-L295返回any or SpyObj<T>, and a SpyObj只定义了methods被监视:

type SpyObj<T> = T & {
    [K in keyof T]: T[K] extends Func ? T[K] & Spy<T[K]> : T[K];
               // |     if it's a     |    spy on it     | otherwise leave
               // |     callable      |                  | it alone
};

所以要访问.and在描述符的 getter 上,你需要可选链接 https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-7.html#optional-chaining (as Object.getOwnPropertyDescriptor可能会回来undefined) and a 类型断言 https://www.typescriptlang.org/docs/handbook/basic-types.html#type-assertions to a Spy https://github.com/DefinitelyTyped/DefinitelyTyped/blob/d063d0175b3eb59a7a4cc5e64992f8a220d9a910/types/jasmine/index.d.ts#L959-L965:

(Object.getOwnPropertyDescriptor(obj, "x")?.get as Spy<() => number>).and.returnValue(7);

操场 https://www.typescriptlang.org/play?#code/DYUwLgBA9gRgVhAvBAxgJxAQzCAygBwE8B5eACgCIBbE+EFMCgGggG8BfF1iADwC4IAZhaEBAFgjsAlAG4AUHLKk49MADoA5uGIB3AHYAFNFHwg0YQgBEQAZ3QBLfGChoysOCwo8KUgPybwCEwbCAJCAB4yKSQAPgg9AFcqGDMYqTVMPQATNQwwBLQ9ADVMYASQMgB2WQUAelqAWiaIG3yYCHsqfFAqED0wbHsoPWgAM1QMbDwiZQgdezAAC1QXDAYIC1MFUYS9BiGR9CwcMOVwgBUYshhgkAA5TF6BVrR7PQ0WXqWoLIfemwEp3gAFlwIsfn9bBcYix8MZTOZCJCbL5ATN4EYTGYLMjoVI0bQ4NC2HIIGSIHkCiNuDcbPdHiBPmCIQybLD4dikazJEEQplCPJ2HVGs0oEszCsiA18MEBhBRsYqBBFmAwPgAfUNAtFgkYGoUFAqLVrKM3gsQMBCOdCKYssaQKa9ObLdbbbUYMBYLUsgAGABsgl9AEZKgBWGCCEAwUMATkwlUwYhQKFDID9YhjMYATKMAByYLNZn1ZOMxoM+2qbWy1ODBKhvEC1N5ZEA8NQ5MA2BRViAAMV2KCQEDIalHmDQGgBQT0hAA2gBdaKIOL8+RyHtAuCg76-VkXIe7FuOkBZOKIUnk84QVs4bIhQ8OhtZCC+C9ksgAJSwWWGloAgmgaCYBELxvBocQAD5sBAs5fOCu5PC0YCvO884CPykjRHwb7Dl+mA-no-6AcB4QANYgIQUDjJcEBQdws4GB0IzkZR1HzqiEDnAx87Xjwt5ZCE-Z7C+EBfvkhSuiAFzcXE6Ezpha4buicCYgiOJ7leyAPsep5IDhV43n0AkQNpT4vjhn7fr+hAAUBIHIWBkHQbOcJYoikLPA5qFyYQmEQNh5K4VZhE2cREQsVRnFOfRjFvBAEVsRxXEGDx0iKTaIChMpxLIFeABkJKBbOADSTHxRRkXnGhnElTxhl3n2A4iVxxU8QVYTSa1sk1a1gprm8OBoKMmAoJlADCpTADY4S9iM9XGUJKBxKwOG1AAVGtEAAEK+SgiyYGa7wbIsmU2EQczaqgk02BkM5RCw8zAMAFLgFS8qlHSHTjOKLTnftIR6GKEApH0V1PSeQSQJNLCZM+4ojMh5TQHsmXYBAoCysjmUoJNyqYPgph6DdEBrbUOH8lEAgwFAUAY3o8iBetm07ag+2HRox2ned8xLGDU36lAuxgPdF1PS94kIyd8RJCkaBjBsnS2Jzv2+TowR8xDpM4QaQuU9LyRmAz5JM9tu1s06R0-WdquXTjT03eOk69i4IuPc9lKFMrjtJH0nYQDKNh0nDUB8-rstMS2PAk2TgWOzYzuuM2rYCIkBtoPiEAGOODKDdNs0xEbZImyze0HRbHNW9ztvXRkT0AZOrv2GLHuS6jE4+-0ITOEEYt21N0fk3XE42HreEEURdnhFnQFfGYed6DEBerRtpus2XYHK9bF2833DtPY3zevZ7P0Gv0N7Dj9Sz2DY0Sw0E7e9J3-vBEHPfPbvA+x-vGdj9ZtkkRNJ6ABJPQowoAzQXkvRmK8S7mw3pXG2O8a5UCgK0L8o1+gH3dkfVuKwz58QvlLK+N9pzPm9o-P2YC5Y-RQa0F6GDIB90-uSWhYB0G+z1oA4AICwEQKgcbGBZt16WyllvHmyxd5qFNGgVoWDxZvRPsMHABCyCX0WNfW+2R74aA7pQlwytpF0KYVrQKhjhYZy4Tw8B+dC4QGLkI9mm8q5IPtrkWw4A5EoAxjIt+GwgIoFIhvKhQQVbMLJBgOk5iBAADcoD2CyLYk2uBAjENCd3H8ISbD7SelAHQqBPR6EypFchvsQgB1ft3LAe0mKxJxmAA4agwktEwNEkA9ddE2B2iUMoFQM6xPiYKBQA0zDDVGhASxoDrFzT4kZQSA5lrL02ucKWp9lGQFUUQ9RJDgkn1xiY8k7hVA+USSvP8YsSlP3KRDbuuyxb7LJHHAQ08c5zz4ScpZUsW4QGiaUJGkVbnPXufIwo3TygCDElSSSby5BCjkMMoaI1MphD-NkCBvF+JzL2AswK8TfYLFEEhFCGg1zQOZg48uTjEHLFhvqSayzjAJA0IsFgCDRbPVaE3Z6yERqkV8R-buCxgYJEgHFfCWQFgHA6JAN2EAWygA0FMDYIcfojXyKUDoXQei+0GMMRpQK+70sFkyvWHUbGLNXqXRxrLxGkLcRLUFjI+XXSVQYgc9ThhsuBSMTAv16D2FNIOH5PS9Ux3JC3B1ZAg3gpwVC-OGdTUL3eRauBIiuZUtteG35tgYa92dTcqWOw9jupGDKr5Z0-UBu+VmkIcUXAtjlkLJuUqXojROl3KWRl5Y-S+UG8oIRgDX3UE0zNPSR6jjUL22wAh-4RAhRJDKfC0gEmhaS5NwiK6iOcdS7ItKnq9kwORHN7883Ks3TbMWcqQAKpwC6q2CQCYDohoW-Yuqml933eRMgow9ACFmvGogK6BFLItFys9Lqvk+tcvWT6ETabRPgaermFb7AQ0nXME6Iw3ixPIjkYdtg4MgHOFASNpQOKYmgyeOdehY0L3-REM1q7zggcpeBnBISoPX0yhgFQ+wjo2srsh1DWb0Ogyw1AHDIacLcdUAAdW1CR4AZHFScayF+HjYAaNLqyvRxN5rYHrpYzamlSxjA6AAKKARcEevmXdEOhJlSZ3JTjBPPknZJwKjnzOWdcFQGwGhPJEtohACzxh04EiTTJjDIS+4bxeFMDQvlr4mVfsEn11sWVSxcPYLUeh1WtF1DADeKR9rwf0TjEYKQvUQzRhhepvRt7bpyPlvUTTmsmqIIM9cGVM7KaDlRmj6LZmNSxXpQKs1BsNTICOMcw8fILiXHEcjnGAAy9hyLhDeKMCU5wvw2ASMAMAaRmq7f25AFOIBWloHSqYHrhoVNqdUAN+amKX0L1G+Scbz3hzTYyLN6cc5FyxFuxR1b63dikUBvoI7vh-v+XiBdw23ZuvAmwKXD0bTh58KHJ9mZk3x2PKYltuWBgFuw5h-RUqcUEqZ2qgYWqQW-w2EIFQL4rwUAo7AHtMw4R+RxHYHDwpl3+pnwRWMxnzPWf2HZ6jk6aALgOuxeSYIEvwBs453tNw4o0ACHOA6lgKAEitENEx1oc9o34T-mFcIY1DfOCoGZgAjgkUo+KTeDS09TWmWB6Y4VrDYeshSiO4C8hoXwetQLvE6z2G3Rv7dO5dxYN3EpkBfvsDIsAPkWB0lPlkHypPPd0yC-0hJQyRejKRQBnHGLhuDmQItRX75x0yhnlOZ5s8ZF8J-jGhdZrybZAJCirIgGyS7wEFw+e-CyTiPrmOmbk4BDq-2ujmfnfl1mqFEAA

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

具有属性的 jasmine.createSpyObj 的相关文章

随机推荐

  • innerHTML 将 CDATA 转换为注释

    我正在尝试使用 javascript 将一些 HTML 插入到页面中 并且我插入的 HTML 包含 CDATA 块 我发现 在 Firefox 和 Chrome 中 CDATA 正在转换为注释 HTML 不在我的控制之下 所以我很难避免使用
  • 在不知道编码的情况下如何读取编码头?

    如果我正在读取 HTML 文件的 XML 我是否必须读取告诉我编码的标签才能读取该文件 该标签的编码方式与文件的编码方式不一样吗 我很好奇你如何在不知道编码的情况下读取该标签 我意识到这个问题已经解决了 我只是好奇它是如何完成的 Updat
  • 在计算机上找不到 MySQL

    我最近直接从网站 mysql 5 7 9 osx10 10 x86 64 dmg 安装了MySQL 并且在尝试更改给定密码时遇到了很大的困难 返回的错误是 警告 在命令行界面上使用密码可能会导致 没有安全感 mysqladmin 连接到 l
  • Java:从 FTP 服务器访问文件

    我有一个 FTP 服务器 里面有一堆文件夹和文件 我的程序需要访问该服务器 读取所有文件并显示它们的数据 出于开发目的 我一直在使用硬盘驱动器上 src 文件夹中的文件 但现在服务器已启动并运行 我需要将软件连接到它 基本上我想要做的是获取
  • 是否可以获取 Stream 中的下一个元素?

    我正在尝试转换for loop到功能代码 我需要向前看一个值 也需要向后看一个值 是否可以使用流 以下代码是将罗马文本转换为数值 不确定带有两个 三个参数的reduce方法是否可以在这里提供帮助 int previousCharValue
  • 在 Windows 环境中使用 Gnustep 在 Objective-C 中进行编程

    我正在使用 Windows 并且想开始学习如何使用 Objective C 进行编程 我安装了 Gnustep 但无法确定如何构造和构建项目 等效 也找不到 IDE 请参阅Gnustep 入门 https stackoverflow com
  • 选择com的理由

    我想知道为什么人们会选择 Com 作为他的软件开发 技术 我的第一个想法是机器 编程语言的独立性 你的是啥呢 COM 是 Windows 上自动化和 IPC 的事实上的标准 尽管 Net 已经开始转移焦点 因此有些领域您根本没有 或没有 选
  • 在python中查找关键字后的单词[重复]

    这个问题在这里已经有答案了 我想查找出现在关键字 由我指定和搜索 之后的单词并打印出结果 我知道我应该使用正则表达式来做到这一点 我也尝试了一下 如下所示 import re s hi my name is ryan and i am ne
  • 如何从 Django 中的请求对象获取 URI?

    如何从 Django 中的请求对象获取 URI 有 request uri 吗 request META REQUEST URI or request get full path 你往往会产生大量琐碎的问题 你可以在文档 谷歌中轻松找到答案
  • NSTokenField 捕获一些 NSEvents

    我需要为 NSTokenField 和解决方案实现 Command Enter Command O 和 Esc 快捷键https stackoverflow com a 18486965 1067147 https stackoverflo
  • 如何使用 Javascript 访问网络摄像头 [重复]

    这个问题在这里已经有答案了 我用谷歌搜索了很长一段时间关于这个话题 没有任何令人满意的结果 实际上我的基本问题是 有没有可能使用 Javascript 访问网络摄像头 也许用 HTML5
  • jQuery .val() 与 .attr("value")

    我本来以为这两个是一样的 但看起来不是 我一般都用过 obj attr value 使用表单字段 但在我当前正在构建的页面上 obj attr value 不返回我在字段中输入的文本 然而 obj val does 在我构建的另一个页面上
  • 自定义验证错误的自动响应

    在 asp net core 2 1 中 当发生验证错误时 ApiController 将自动响应 400 BadRequest 如何更改 修改发送回客户端的响应 json body 有某种中间件吗 我正在使用 FluentValidati
  • 使用 Celery(RabbitMQ、Django)检索队列长度

    我在 django 项目中使用 Celery 我的代理是 RabbitMQ 我想检索队列的长度 我浏览了 Celery 的代码 但没有找到执行此操作的工具 我在 stackoverflow 上发现了这个问题 从客户端检查 RabbitMQ
  • 在 go 中使用来自网络的原始字节

    抱歉 问题很长 我最近一直在尝试使用 Go 而不是 C 来开发一个游戏服务器模拟器 我正在将其作为一个业余项目进行开发 并质疑我是否以合理的 Go 术语来实现它 正如您所料 服务器通过发送符合特定协议规范的原始数据包 TCP 与一个或多个游
  • Xcode UI 测试 - 使用存储的凭据登录/注销

    我想在我的 iOS 应用程序 Xcode 7 2 1 中运行登录过程的功能 UI 测试 该应用程序的行为是 成功登录后 将存储用户凭据 以便在下次启动时自动登录 不显示登录屏幕 因此 我在登录屏幕中设置了一系列 UI 事件 以使应用程序首次
  • 如何避免 TYPO3 中的日期时间问题?

    我创建了一个小扩展 它使用日期时间来查看一些特定事件 事件日期和事件时间 但如果我尝试从数据库获取正确的日期时间到前端 我总是会遇到麻烦 我可以通过 TYPO3 后端设置每个事件的日期时间 但是如果我尝试在前端获取这个值 例如
  • 从多个自左连接中删除重复项

    我正在动态生成如下所示的查询 该查询通过对其自身进行左连接 任意次数 来创建不同的规则组合 并避免使用某些相同属性作为连接条件的一部分的规则 例如 SELECT count FROM rules AS t1 LEFT JOIN rules
  • Bool.hashValue 转换为 Int 有效吗?

    在某些情况下和一些代码我看到hashValue用于转换Bool to Int 然而 代码 let someValue true let someOtherValue false print someValue hashValue print
  • 具有属性的 jasmine.createSpyObj

    在我的 Angular 测试中模拟依赖项时 我通常使用以下命令创建一个间谍对象jasmine createSpyObj const serviceSpy jasmine createSpyObj MyService method 然后将其提