如何在angular 2中测试私有函数?

class FooBar {

    private _status: number;

    constructor( private foo : Bar ) {
        this.initFooBar();

    }

    private initFooBar(){
        this.foo.bar( "data" );
        this._status = this.fooo.foo();
    }

    public get status(){
        return this._status;
    }

}

我找到了解决办法

将测试代码本身放在闭包中,或者在闭包中添加代码,以存储外部作用域中现有对象上局部变量的引用。 稍后使用工具提取测试代码。 http://philipwalton.com/articles/how-to-unit-test-private-functions-in-javascript/

如果你做过这个问题,请给我一个更好的解决方法。

P.S

大多数类似类型的问题的答案都没有给出问题的解决方案,这就是我问这个问题的原因 大多数开发人员说不要测试私有函数,但我不会说它们是错的还是对的,但我的案例中有必要测试私有函数。


当前回答

你可以调用私有方法!

如果您遇到以下错误:

expect(new FooBar(/*...*/).initFooBar()).toEqual(/*...*/)
// TS2341: Property 'initFooBar' is private and only accessible within class 'FooBar'

只需使用// @ts-ignore:

// @ts-ignore
expect(new FooBar(/*...*/).initFooBar()).toEqual(/*...*/)

感谢@Moff452的评论。你也可以这样写:

expect(new FooBar(/*...*/)['initFooBar']()).toEqual(/*...*/)

更新:

@ts-expect-error是@ts-ignore的更好选择。看到的: https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-9.html#ts-ignore-or-ts-expect-error

其他回答

我同意@toskv的观点:我不建议这么做:-)

但是如果你真的想测试你的私有方法,你可以意识到TypeScript的相应代码对应于构造函数原型的一个方法。这意味着它可以在运行时使用(然而您可能会有一些编译错误)。

例如:

export class FooBar {
  private _status: number;

  constructor( private foo : Bar ) {
    this.initFooBar({});
  }

  private initFooBar(data){
    this.foo.bar( data );
    this._status = this.foo.foo();
  }
}

将转化为:

(function(System) {(function(__moduleName){System.register([], function(exports_1, context_1) {
  "use strict";
  var __moduleName = context_1 && context_1.id;
  var FooBar;
  return {
    setters:[],
    execute: function() {
      FooBar = (function () {
        function FooBar(foo) {
          this.foo = foo;
          this.initFooBar({});
        }
        FooBar.prototype.initFooBar = function (data) {
          this.foo.bar(data);
          this._status = this.foo.foo();
        };
        return FooBar;
      }());
      exports_1("FooBar", FooBar);
    }
  }
})(System);

查看这个plunkr: https://plnkr.co/edit/calJCF?p=preview。

不要为私有方法编写测试。这就破坏了单元测试的意义。

您应该测试类的公共API 你不应该测试类的实现细节

例子

class SomeClass {

  public addNumber(a: number, b: number) {
      return a + b;
  }
}

如果之后实现发生变化,但公共API的行为保持不变,则该方法的测试不需要更改。

class SomeClass {

  public addNumber(a: number, b: number) {
      return this.add(a, b);
  }

  private add(a: number, b: number) {
       return a + b;
  }
}

不要仅仅为了测试而将方法和属性设为公共。这通常意味着:

您正在尝试测试实现,而不是API(公共接口)。 您应该将所讨论的逻辑移到它自己的类中,以使测试更容易。

使用方括号调用私有方法。

Ts文件

class Calculate{
  private total;
  private add(a: number) {
      return a + total;
  }
}

spect。ts文件

it('should return 5 if input 3 and 2', () => {
    component['total'] = 2;
    let result = component['add'](3);
    expect(result).toEqual(5);
});

正如许多人已经指出的那样,尽管您想要测试私有方法,但您不应该通过修改代码或编译器来让它为您工作。现代的TypeScript会拒绝人们迄今为止提供的大部分hack。


解决方案

TLDR;如果一个方法需要测试,那么您应该将代码解耦到一个类中,以便将该方法公开以供测试。

你拥有私有方法的原因是因为功能不一定属于那个类,因此如果功能不属于那里,它应该解耦到它自己的类中。

例子

我偶然看到了这篇文章,它很好地解释了应该如何处理私有方法的测试。它甚至涵盖了这里的一些方法,以及为什么它们是糟糕的实现。

https://patrickdesjardins.com/blog/how-to-unit-test-private-method-in-typescript-part-2

注意:这段代码摘自上面链接的博客(我复制了以防链接后面的内容发生变化)

之前

class User {
    public getUserInformationToDisplay() {
        //...
        this.getUserAddress();
        //...
    }
 
    private getUserAddress() {
        //...
        this.formatStreet();
        //...
    }

    private formatStreet() {
        //...
    }
}

class User {
    private address: Address;

    public getUserInformationToDisplay() {
        //...
        address.format();
        //...
    }
}

class Address {
    private format: StreetFormatter;

    public format() {
        //...
        format.toString();
        //...
    }
}

class StreetFormatter {
    public toString() {
        // ...
    }
}

结束笔记

You can implicitly test your private methods by making sure that conditions are met such that the code is called through the public interface. If the public interface does not call out to the private methods then that code is not providing any function and should be removed. In the example above there should be some effect that calling the private method should return ie: an object with an address. If there's not, for example the code emits an event in a private method, then you should start looking to decouple that so that it can be tested -- even in that example you would likely listen/subscribe to that event and would be able to test it that way. Decoupling leads to better testability and easier code maintenance later down the road as well.

Aaron的答案是最好的,对我来说也很有用:) 我会给它投票,但遗憾的是我不能(失去声誉)。

我不得不说,测试私有方法是使用它们并在另一方面有干净代码的唯一方法。

例如:

class Something {
  save(){
    const data = this.getAllUserData()
    if (this.validate(data))
      this.sendRequest(data)
  }
  private getAllUserData () {...}
  private validate(data) {...}
  private sendRequest(data) {...}
}

不一次测试所有这些方法是很有意义的,因为我们需要模拟出那些私有方法,我们不能模拟出来,因为我们不能访问它们。这意味着我们需要对一个单元测试进行大量的配置,以将其作为一个整体进行测试。

这就是说,测试上述方法的所有依赖关系的最佳方法是端到端测试,因为这里需要集成测试,但如果您正在实践TDD(测试驱动开发),则端到端测试对您没有帮助,但测试任何方法都有帮助。