在 TypeScript 中模拟只读 Flux 存储 属性
Mocking read-only Flux store property in TypeScript
我正在使用 React、Flux 和 TypeScript 创建一个应用程序。我正在使用 Karma 和 Jasmine 进行测试。
我有一家商店,像这样:
class MemberStore {
private _members:Member[];
public get members():Member[] { return this._members; }
}
与所有 Flux 存储一样,数据是只读的,可以通过操作处理程序(未显示)修改,而不是设置器。
我想在依赖于 MemberStore
的代码单元测试中模拟此数据存储。但是,由于 members
是只读的,我不能这样做:
var mockMemberStore:MemberStore = jasmine.createSpyObj("MemberStore");
mockMemberStore.members = [/*mock members*/];
上面的代码实际上发出了有效的 JS,因为 mockMemberStore
实际上不是 MemberStore
的一个实例,而是一个 Jasmine 间谍对象(和 createSpyObj
returns any
). 但是,它在 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. In the above example I replace MemberStore
completely with a jasmine SpyObj, which works. 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. Example
我可以将其更改为 var mockMemberStore:any
,或者使用像 (<any> mockMemberStore).members = []
这样的转换,但是编译器不会将 members
视为对 ModelStore/members
的引用,所以所有静态类型检查丢失(并且 "find references" 和 "refactor/rename" 之类的东西不起作用)。这里使用的方法是什么?
你应该会写:
(mockMemberStore as any).members = [""];
这不会更改任何未来对 mockMemberStore
的引用的类型。因为这是一个单元测试,所以代码不需要像平时那样完美。重要的是,如果你引入错误,它就会失败,在这种情况下,它会失败:如果你执行无效重构,renamedMembers
将不再设置,测试应该失败,你将能够修复它。
这并不理想,因为您确实丢失了查找用法,但它并不像其他语言中经常出现的那样糟糕(模拟只读对象非常麻烦)。
接口对此很有用:
interface IMemberStore {
members: Member[];
}
class MemberStore implements IMemberStore {
private _members:Member[];
public get members():Member[] { return this._members; }
}
class MockMemberStore implements IMemberStore {
members: Member[];
}
在您的大部分应用程序中使用 IMemberStore
,使用 MemberStore
作为实现,并在您的单元测试中使用 MockMemberStore
。
我正在使用 React、Flux 和 TypeScript 创建一个应用程序。我正在使用 Karma 和 Jasmine 进行测试。
我有一家商店,像这样:
class MemberStore {
private _members:Member[];
public get members():Member[] { return this._members; }
}
与所有 Flux 存储一样,数据是只读的,可以通过操作处理程序(未显示)修改,而不是设置器。
我想在依赖于 MemberStore
的代码单元测试中模拟此数据存储。但是,由于 members
是只读的,我不能这样做:
var mockMemberStore:MemberStore = jasmine.createSpyObj("MemberStore");
mockMemberStore.members = [/*mock members*/];
上面的代码实际上发出了有效的 JS,因为 mockMemberStore
实际上不是 MemberStore
的一个实例,而是一个 Jasmine 间谍对象(和 createSpyObj
returns any
). 但是,它在 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. In the above example I replaceMemberStore
completely with a jasmine SpyObj, which works. If instead I simply try tospyOn
a real version ofMemberStore
, that's when I see a runtime error thatmembers
cannot be assigned. Example
我可以将其更改为 var mockMemberStore:any
,或者使用像 (<any> mockMemberStore).members = []
这样的转换,但是编译器不会将 members
视为对 ModelStore/members
的引用,所以所有静态类型检查丢失(并且 "find references" 和 "refactor/rename" 之类的东西不起作用)。这里使用的方法是什么?
你应该会写:
(mockMemberStore as any).members = [""];
这不会更改任何未来对 mockMemberStore
的引用的类型。因为这是一个单元测试,所以代码不需要像平时那样完美。重要的是,如果你引入错误,它就会失败,在这种情况下,它会失败:如果你执行无效重构,renamedMembers
将不再设置,测试应该失败,你将能够修复它。
这并不理想,因为您确实丢失了查找用法,但它并不像其他语言中经常出现的那样糟糕(模拟只读对象非常麻烦)。
接口对此很有用:
interface IMemberStore {
members: Member[];
}
class MemberStore implements IMemberStore {
private _members:Member[];
public get members():Member[] { return this._members; }
}
class MockMemberStore implements IMemberStore {
members: Member[];
}
在您的大部分应用程序中使用 IMemberStore
,使用 MemberStore
作为实现,并在您的单元测试中使用 MockMemberStore
。