我同意你的观点,尽管“只对公共API进行单元测试”是一个很好的目标,但有时它看起来并不那么简单,你会觉得你在API和单元测试之间做出选择。你已经知道了,因为这正是你想要做的,所以我就不多说了。:)
在TypeScript中,我发现了一些为了单元测试而访问私有成员的方法。考虑这个类:
class MyThing {
private _name:string;
private _count:number;
constructor() {
this.init("Test", 123);
}
private init(name:string, count:number){
this._name = name;
this._count = count;
}
public get name(){ return this._name; }
public get count(){ return this._count; }
}
尽管TS使用private、protected、public来限制对类成员的访问,但编译后的JS没有private成员,因为这在JS中是不存在的。它纯粹用于TS编译器。因此:
You can assert to any and escape the compiler from warning you about access restrictions:
(thing as any)._name = "Unit Test";
(thing as any)._count = 123;
(thing as any).init("Unit Test", 123);
The problem with this approach is that the compiler simply has no idea what you are doing right of the any, so you don't get desired type errors:
(thing as any)._name = 123; // wrong, but no error
(thing as any)._count = "Unit Test"; // wrong, but no error
(thing as any).init(0, "123"); // wrong, but no error
This will obviously make refactoring more difficult.
You can use array access ([]) to get at the private members:
thing["_name"] = "Unit Test";
thing["_count"] = 123;
thing["init"]("Unit Test", 123);
While it looks funky, TSC will actually validate the types as if you accessed them directly:
thing["_name"] = 123; // type error
thing["_count"] = "Unit Test"; // type error
thing["init"](0, "123"); // argument error
To be honest I don't know why this works. This is apparently an intentional "escape hatch" to give you access to private members without losing type safety. This is exactly what I think you want for your unit-testing.
下面是TypeScript Playground中的一个工作示例。
编辑为TypeScript 2.6
另一个选项是使用// @ts-ignore(在TS 2.6中添加),它简单地抑制了下面一行的所有错误:
// @ts-ignore
thing._name = "Unit Test";
这样做的问题是,它抑制了下面一行的所有错误:
// @ts-ignore
thing._name(123).this.should.NOT.beAllowed("but it is") = window / {};
我个人认为@ts-ignore是一种代码气味,正如文档所说:
我们建议您尽量少使用这些注释。(强调原创)