简体   繁体   English

在TypeScript中模拟只读Flux商店属性

[英]Mocking read-only Flux store property in TypeScript

I'm creating an app using React, Flux, and TypeScript. 我正在使用React,Flux和TypeScript创建一个应用程序。 I'm testing using Karma and Jasmine. 我正在使用Karma和Jasmine进行测试。

I have a Store, like this: 我有一家商店,像这样:

class MemberStore {
    private _members:Member[];
    public get members():Member[] { return this._members; }
}

As with all Flux stores, data is read-only and modified through action handlers (not shown), not setters. 与所有Flux商店一样,数据是只读的,并通过操作处理程序(未显示)而不是设置程序进行修改。

I would like to mock this data store in a unit test of code that depends on MemberStore . 我想在依赖MemberStore的代码的单元测试中模拟此数据存储。 However, since members is read-only I cannot do something like this: 但是,由于members是只读的,因此我无法执行以下操作:

var mockMemberStore:MemberStore = jasmine.createSpyObj("MemberStore");
mockMemberStore.members = [/*mock members*/];

The above code actually emits working JS, since mockMemberStore is not actually an instance of MemberStore but a Jasmine spy object (and createSpyObj returns any ). 上面的代码实际上发出工作JS,因为mockMemberStore实际上不是的一个实例MemberStore但茉莉间谍对象(和createSpyObj返回any )。 However, it generates a compile-error on mockMemberStore.members = [] because it's a read-only property. 但是,由于它是只读属性,因此会在mockMemberStore.members = []上生成编译错误。

EDIT: So it turns out I was mis-reading the error, and it was not this code that gave an error. 编辑:原来我错读了错误,并且不是该代码提供了错误。 It was not a compile error, it's a runtime error. 这不是编译错误,而是运行时错误。 Surprisingly, TSC doesn't care if I assign a value to members at compile time, even though it's read-only. 出乎意料的是,即使我是只读的,TSC也不在乎是否在编译时为members分配值。 In the above example I replace MemberStore completely with a jasmine SpyObj, which works. 在上面的例子中,我代替MemberStore完全茉莉花SpyObj,它的工作原理。 If instead I simply try to spyOn a real version of MemberStore , that's when I see a runtime error that members cannot be assigned. 如果相反,我只是尝试spyOn一个真实版本的MemberStore ,那就是当我看到无法分配members的运行时错误时。 Example

I could change it to var mockMemberStore:any , or use casting like (<any> mockMemberStore).members = [] , but then the compiler doesn't see members as a reference to ModelStore/members so all static type checking is lost (and things like "find references" and "refactor/rename" don't work). 我可以将其更改为var mockMemberStore:any ,也可以使用(<any> mockMemberStore).members = [] ,但是随后编译器没有将members视为对ModelStore/members的引用,因此所有静态类型检查都将丢失(并且“查找引用”和“重构/重命名”之类的内容不起作用)。 What is the approach to use here? 在这里使用什么方法?

You should be able to write: 您应该能够写:

(mockMemberStore as any).members = [""];

This will not change the type of any future references to mockMemberStore . 这将不会更改任何将来对mockMemberStore引用的类型。 Because this is a unit test, the code does not need to be as perfect as it usually is. 由于这是一个单元测试,因此代码不需要像通常那样完美。 The important thing is that it will fail if you introduce an error, and in this case, it will fail: if you perform an invalid refactor, renamedMembers will no longer be set and the test should blow up, and you will be able to fix it. 重要的是,如果引入错误,它将失败,并且在这种情况下,它将失败:如果执行无效的重构,则将不再设置renamedMembers ,并且测试应该renamedMembers ,并且您将能够修复它。

This is not ideal, since you do lose find-usages, but it's not as bad as it often is in other languages (mocking readonly objects is notoriously cumbersome). 这是不理想的,因为您会丢失查找用例,但是它并不像其他语言中那样糟糕(众所周知,嘲笑只读对象很麻烦)。

Interfaces are useful for this: 接口对此非常有用:

interface IMemberStore {
    members: Member[];
}

class MemberStore implements IMemberStore {
    private _members:Member[];
    public get members():Member[] { return this._members; }
}

class MockMemberStore implements IMemberStore {
    members: Member[];
}

Use IMemberStore in most of your application, use MemberStore as the implementation, and use MockMemberStore in your unit tests. 使用IMemberStore在大多数应用程序,使用MemberStore作为实现,并使用MockMemberStore在单元测试中。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM