如何在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

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


当前回答

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

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);
});

其他回答

由于大多数开发人员不建议测试私有函数,为什么不测试它呢?

Eg.

YourClass.ts

export class FooBar {
  private _status: number;

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

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

TestYourClass.spec.ts

describe("Testing foo bar for status being set", function() {

...

//Variable with type any
let fooBar;

fooBar = new FooBar();

...
//Method 1
//Now this will be visible
fooBar.initFooBar();

//Method 2
//This doesn't require variable with any type
fooBar['initFooBar'](); 
...
}

感谢@Aaron, @Thierry Templier。

正如许多人已经指出的那样,尽管您想要测试私有方法,但您不应该通过修改代码或编译器来让它为您工作。现代的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.

这招对我很管用:

而不是:

sut.myPrivateMethod();

这样的:

sut['myPrivateMethod']();

我采用的这种方法是在类外部创建函数,并将函数分配给我的私有方法。

export class MyClass {
  private _myPrivateFunction = someFunctionThatCanBeTested;
}

function someFunctionThatCanBeTested() {
  //This Is Testable
}

现在我不知道我破坏了哪种类型的OOP规则,但是为了回答这个问题,这是我测试私有方法的方法。我欢迎任何人就利弊提出建议。

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

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);
});