angular - 如何使用 Jasmine 为私有(private)方法编写 Angular/TypeScript 的单元测试

标签 angular unit-testing typescript jasmine

如何在 Angular 2 中测试私有(private)函数?

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

}

我找到的解决方案

  1. 将测试代码本身放入闭包内或将代码添加到闭包内,闭包存储对外部作用域中现有对象的局部变量的引用。

    稍后使用工具剥离测试代码。 http://philipwalton.com/articles/how-to-unit-test-private-functions-in-javascript/

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

附言

  1. 大多数类似问题的答案都没有给出问题的解决方案,这就是我问这个问题的原因

  2. 大多数开发者都说你不要测试私有(private)函数,但我不说他们是错的还是对的,但我的案例有测试私有(private)的必要性。

最佳答案

我同意你的看法,尽管“只对公共(public) API 进行单元测试”是一个很好的目标,但有时它看起来并不那么简单,你觉得你在妥协 API 或单元之间做出选择-测试。您已经知道这一点,因为这正是您要执行的操作,所以我不会深入探讨。 :)

在 TypeScript 中,为了进行单元测试,我发现了几种访问私有(private)成员的方法。考虑这个类:

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 使用 privateprotectedpublic 限制对类成员的访问,编译后的 JS 没有私有(private)成员,因为这是不是 JS 的东西。它纯粹用于 TS 编译器。为此:

  1. 您可以对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
    

    这显然会使重构变得更加困难。

  2. 您可以使用数组访问 ([]) 获取私有(private)成员:

    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"让您在不失去类型安全的情况下访问私有(private)成员。这正是我认为您想要的单元测试。

这是一个working example in the TypeScript Playground .

为 TypeScript 2.6 编辑

有些人喜欢的另一种选择是使用 //@ts-ignore ( added in TS 2.6 ),它可以简单地抑制以下行中的所有错误:

// @ts-ignore
thing._name = "Unit Test";

这个问题是,好吧,它抑制了以下行中的所有错误:

// @ts-ignore
thing._name(123).this.should.NOT.beAllowed("but it is") = window / {};

我个人认为 @ts-ignore 是一种代码味道,正如文档所说:

we recommend you use this comments very sparingly. [emphasis original]

关于angular - 如何使用 Jasmine 为私有(private)方法编写 Angular/TypeScript 的单元测试,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35987055/

相关文章:

unit-testing - 如何对私有(private)变量进行单元测试?

java - 集成测试中 Spring Controller 中的 Mock Feign 客户端

javascript - Jasmine/Jest 类型冲突

typescript - Webpack 找不到模块 'electron'

forms - 如何验证至少应选中一个复选框?

angular - 使用 Angular Material 2 动态创建卡片网格

javascript - MatDialog 服务单元测试 Angular 6 错误

angular - 在 Angular 6 工作空间中安装 NPM 包

asp.net - 为 asp.net web 应用程序编写单元测试

angular - 在 Angular 4 中,如何将 FormGroup 转换为带有查询参数的 URL?