如何在 Typescript 中对私有方法进行单元测试
Posted
技术标签:
【中文标题】如何在 Typescript 中对私有方法进行单元测试【英文标题】:How to unit test private methods in Typescript 【发布时间】:2018-08-01 01:37:56 【问题描述】:当我尝试对类中的私有方法进行单元测试时,由于私有方法只能在类中访问而出错。在这里,我为我的班级和 mocha 测试添加了示例 sn-p。请为我提供实现私有方法单元测试的解决方案。
类名:Notification.ts
class Notification
constructor()
public validateTempalte()
return true;
private replacePlaceholder()
return true;
单元测试:
import Notification from 'Notification';
import * as chai from "chai";
describe("Notification", function()
describe('#validateTempalte - Validate template', function()
it('it should return success', function()
const result = new Notification()
chai.expect(result.validateTempalte()).to.be.equal(true);
);
);
describe('#replacePlaceholder - Replace Placeholder', function()
it('it should return success', function()
const result = new Notification()
// As expected getting error "Private is only accessible within class"
chai.expect(result.replacePlaceholder()).to.be.equal(true);
);
);
);
作为一种解决方法,目前,我正在将函数 replacePlaceholder 的访问说明符更改为 public。但我不认为这是一种有效的方法。
【问题讨论】:
你不应该,测试应该只覆盖你单元的公共接口。 【参考方案1】:在 HolgerJeromin 的评论中,comment issue 有一个简洁的解决方案,仍然使用属性语法。
解决方案是将您的对象/类类型转换为any
。
例子:
(<any>myClass).privateMethod();
const value = (<any>myClass).privateValue;
(myClass as any).privateMethod();
const value = (myClass as any).privateValue;
此方法满足编译器以及VSCode语法高亮。
这是我在issue that talks about this的一些笔记
通过字符串访问更为常见,尽管我不明白为什么它可能更安全。 这些功能是有意完成的,因此它们的帮助多于阻碍。 可能有一种方法可以禁用此类功能,这样人们就不会将此代码复制并粘贴到生产环境中。"noImplicitAny": true,
可能帮助tsconfig.json
【讨论】:
对于 TSX:(myClass as any).privateValue
@MaxReeder 确实!这些解决方案应该适用于所有打字稿环境,包括 .tsx【参考方案2】:
将私有函数提取为单独/独立的函数,但不要将其导出到外部。
这在语义上是正确的,因为毕竟 - 私有函数是私有的,不应被任何人访问,除了类本身。
【讨论】:
【参考方案3】:在我的例子中,我使用对象的原型来访问私有方法。效果很好,TS不骂人。
例如:
class Example
private privateMethod()
describe()
it('test', () =>
const example = new Example();
const exampleProto = Object.getPrototypeOf(example);
exampleProto.privateMethod();
)
如果您使用静态方法,请使用exampleProto.<strong>constructor</strong>.privateMethod();
。
【讨论】:
我花了将近 3 天时间,甚至两次三遍我检查了这个链接但不正确。谢谢安迪。最后命中静态方法对我有帮助。 注意,这不利于测试类实例上的私有属性的值。【参考方案4】:省略 Typescript 检查的一种可能解决方案是动态访问属性(不告诉它好不好)。
myClass['privateProp']
或方法:myClass['privateMethod']()
【讨论】:
是的,如果你使用私有静态方法,你应该使用类,而不是变量,因此应该导出一个类 这是正确的答案,而不是公认的“你可以打电话给他们”。这个满足编译器。 测试私有方法的最佳解决方案 这是单元测试的明确方法:github.com/microsoft/TypeScript/issues/…【参考方案5】:技术上,在当前版本的 TypeScript 中,私有方法仅在编译时检查为私有 - 因此您可以调用它们。
class Example
public publicMethod()
return 'public';
private privateMethod()
return 'private';
const example = new Example();
console.log(example.publicMethod()); // 'public'
console.log(example.privateMethod()); // 'private'
我提到这个只是因为你问怎么做,那是你可以做的。
正确答案
然而,该私有方法必须由其他方法调用...否则根本不会调用它。如果您测试其他方法的行为,您将在使用它的上下文中覆盖私有方法。
如果您专门测试私有方法,您的测试将与实现细节紧密耦合(即,如果您重构实现,则无需更改好的测试)。
免责声明
如果您仍然在私有方法级别进行测试,编译器可能在将来会更改并使测试失败(即,如果编译器将方法“正确”设为私有,或者如果未来ECMAScript 版本添加了可见性关键字等)。
【讨论】:
我经常发现这种论点,但在我看来,这远非现实。如果您有一个复杂的功能,您希望将其拆分为更小的逻辑段以单独测试它们,从而减少开发时间、复杂性、错误的可能性和测试量。解决这个问题的标准方法是将所有段作为函数移动到util
模块中并将它们导出到那里(“那么它们是官方的 util 方法,不是吗?”),这只会混淆潜在的困境并破坏可见范围的逻辑。
@NotX 答案的第一部分涵盖了想要这样做的人......所以我不排除这里的任何人。您看到有关将测试与实现细节紧密耦合的警告(通过过于狭隘地定义“单元”)的原因是,由于测试不应该依赖的细节导致测试失败,因此重构变得非常困难。测试更广泛的单元允许进行不影响测试的广泛更改。它使该过程更像肯特贝克的定义。 2013 年,我以这种方式工作了 5 年,从你的角度背叛了我,而过去的 7 年要快乐得多。
我想说,如果您在更大范围内更改实现细节,那么删除不再适用于新逻辑的测试并没有错。当您开发旧版本的代码时,他们会为您提供帮助。稍后,当您更改内部内容时,您希望用新的测试替换它们,以帮助您正确开发新逻辑。请记住,我在这里谈论的是复杂的函数,其中单个段并非微不足道。
@JasonMcCarrell 我们对隔离有不同的想法。 2013 年,Ian Coopers “TDD 哪里出了问题”的演讲改变了我的想法:stevefenton.co.uk/2013/05/my-unit-testing-epiphany
@Fenton,谢谢你分享这个!你实际上已经引导我走上了一条我相信会非常有益的道路。我以前有相反的心态,但那样编码是令人反感的。 Cooper 解释了对这种 TDD 风格的固有阻力,以及为什么他引用的书中的教义允许快速和安全的测试。我希望这将为我(以及可能遇到此对话的其他人)填补一个新的、更好的编码风格时代的差距!【参考方案6】:
由于私有方法不能在类外部访问,您可以在 Notification 类中使用另一个调用 replacePlaceholder() 的公共方法,然后测试公共方法。
【讨论】:
以上是关于如何在 Typescript 中对私有方法进行单元测试的主要内容,如果未能解决你的问题,请参考以下文章