我同意你的观点,尽管"只对公共API进行单元测试"是一个很好的目标,但有时它似乎并没有那么简单,你会觉得自己在牺牲API或单元测试之间做出 Select .你已经知道这一点了,因为这正是你要求做的,所以我不想插手.:)
在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没有私有成员,因为这在JS中不是一件事.它纯粹用于TS编译器.因此:
您可以断言为any
,并避免编译器警告您访问限制:
(thing as any)._name = "Unit Test";
(thing as any)._count = 123;
(thing as any).init("Unit Test", 123);
这种方法的问题是,编译器根本不知道您在any
中做什么,所以您不会得到想要的类型错误:
(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
这显然会增加重构的难度.
您可以使用数组访问([]
)访问私有成员:
thing["_name"] = "Unit Test";
thing["_count"] = 123;
thing["init"]("Unit Test", 123);
虽然它看起来很时髦,但TSC实际上会验证这些类型,就像您直接访问它们一样:
thing["_name"] = 123; // type error
thing["_count"] = "Unit Test"; // type error
thing["init"](0, "123"); // argument error
说实话,我不知道为什么会这样 这显然是一个intentional "escape hatch",让你在不失go 类型安全的情况下访问私有成员.这正是我认为你想要的单元测试.
这是working example in the TypeScript Playground美元.
Edit for TypeScript 2.6
有些人喜欢的另一个选项是使用// @ts-ignore
(added in TS 2.6),它只会 suppress 以下行中的所有错误:
// @ts-ignore
thing._name = "Unit Test";
问题是,它会 suppress 以下行中的所有错误:
// @ts-ignore
thing._name(123).this.should.NOT.beAllowed("but it is") = window / {};
我个人认为@ts-ignore
的代码气味,正如doctor 说:
我们建议您使用此注释very sparingly.[强调原文]