如何在 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 中对私有方法进行单元测试的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Swift 中对私有或内部函数进行单元测试?

如何使用 Jasmine 为私有方法编写 Angular / TypeScript 单元测试

在 Swift 中对私有变量进行单元测试

如何在目标 c 中对目标的项目级 API 进行单元测试?

如何在 java 中对这个方法进行单元测试?

如何在 C++ 中对受保护的方法进行单元测试?