在私有方法上使用 Jasmine spyon

Posted

技术标签:

【中文标题】在私有方法上使用 Jasmine spyon【英文标题】:using Jasmines spyon upon a private method 【发布时间】:2012-01-18 12:29:44 【问题描述】:

是否可以在类私有方法上使用 Jasmine 单元测试框架的 spyon 方法?

文档给出了这个例子,但这对于私有函数来说可以灵活吗?

describe("Person", function() 
    it("calls the sayHello() function", function() 
        var fakePerson = new Person();
        spyOn(fakePerson, "sayHello");
        fakePerson.helloSomeone("world");
        expect(fakePerson.sayHello).toHaveBeenCalled();
    );
);

【问题讨论】:

【参考方案1】:
spyOn(fakePerson, <never>'sayHello');
spyOn(fakePerson, <keyof Person>'sayHello');

既能消除类型错误,又不会干扰 TSLint 的 no-any 规则。

【讨论】:

【参考方案2】:
const spy = spyOn<any>(component, 'privateMethod');
expect(spy).toHaveBeenCalled();

为避免有关通过字符串文字访问对象的 lint 警告,请创建 spy 对象的本地常量。

【讨论】:

【参考方案3】:
spyOn<any>(fakePerson, 'sayHello');
expect(fakePerson['sayHello']).toHaveBeenCalled();

通过将&lt;any&gt; 添加到 spyOn,您可以将其从 typescript 类型检查中删除。 您还需要使用数组索引符号来访问测试中的私有方法(sayHello)期望

【讨论】:

虽然此代码可能会回答问题,但提供有关它如何和/或为什么解决问题的额外上下文将提高​​答案的长期价值。【参考方案4】:

假设sayHello(text: string) 是一个私有方法。您可以使用以下代码:

// Create a spy on it using "any"
spyOn<any>(fakePerson, 'sayHello').and.callThrough();

// To access the private (or protected) method use [ ] operator:
expect(fakeperson['sayHello']).toHaveBeenCalledWith('your-params-to-sayhello');
使用 any 创建私有方法的间谍。 要访问私有(或受保护)方法,请使用 [] 运算符。

【讨论】:

投了反对票,因为您没有解决主要问题,即您如何监视私有方法。此代码与问题中最初提供的代码并没有什么不同。 @JeffryHouser sayHello 是私有方法。第一行是如何在上面创建一个间谍。第二行是测试。 知道了;您的答案缺少有关如何使用 &lt;any&gt; 标签监视私有方法的说明。这就是我感到困惑的原因。【参考方案5】:

Typescript 被编译成 javascript,并且在 javascript 中每个方法都是公开的。所以你可以使用数组索引符号来访问私有方法或文件,即:

Object['private_field']

【讨论】:

博客链接不幸失效了。 这里投了反对票,部分用于死博客链接;部分原因是我们不能使用对象数组表示法来设置间谍。【参考方案6】:

如果您将 Typescript 用于您的对象,则该函数并不是真正私有的。 您只需保存从spyOn 调用返回的值,然后查询它的calls 属性。

最后,这段代码应该对你有用(至少对我有用):

describe("Person", function() 
    it("calls the sayHello() function", function() 
        var fakePerson = new Person();
        // save the return value:
        var spiedFunction = spyOn<any>(fakePerson, "sayHello");
        fakePerson.helloSomeone("world");
        // query the calls property:
        expect(spiedFunction.calls.any()).toBeFalsy();
    );
);

【讨论】:

如果我尝试调用非导出(私有)函数,则会出现类型错误:Error:(33, 56) TS2345:Argument of type '"sayHello"' is not assignable to parameter of type '"sayGoodbye"'. 其中sayGoodbyePerson 上的公共方法,sayGoodbye 是私有方法。我必须将它转换为任何(“sayHello” as any) 我在这里需要更多上下文,您的任务似乎不起作用并且无法访问私有函数。但请尝试像这样访问它:person["sayHello"] 而不是 person.sayHello(如果您正在这样做)。这不是最佳做法,但在极少数情况下可以原谅 ;) 同意@FlavorScape。 Typescript(至少 1.7 及更高版本)期望被监视的函数是公共的,并且由于 sayHello 不是类型 sayGoodbye(或任何其他公共函数),它会抛出错误。我只能使用上面列出的 spy 来解决这个问题。 自从我上次发表评论以来,情况似乎发生了变化。 spy&lt;any&gt; 可能确实是正确的答案。谢谢 spy&lt;any&gt; 是一个启示。【参考方案7】:

就我而言(打字稿):

jest.spyOn<any, string>(authService, 'isTokenActual')

OR 模拟结果:

jest.spyOn<any, string>(authService, 'isTokenActual').mockImplementation(() => 
  return false;
);

【讨论】:

【参考方案8】:

只需在 spyon() 函数中添加一个通用参数

 spyOn<any>(fakePerson, 'sayHello');

完美运行!

【讨论】:

我试过这个解决方案,效果很好。此外,可以使用数组索引表示法访问私有字段,就像我之前提到的那样。 这些都不适合我。您不能通过数组表示法访问,因为 spyOn 需要两个参数。如图所示放置 也会引发错误数量的参数错误。这对我有用:spyOn(fakePerson as any, 'sayHello'); 我也这样做。有没有更好的方法而不使用任何“通用”?我试过例如 spyOn(fakePerson, 'sayHello');但随后仍然抱怨“打个招呼”。有没有可能像 spyOn 之类的东西?为了更好的背景? 有人能解释一下为什么这个解决方案有效吗?添加&lt;any&gt; 究竟做了什么才能使它起作用? @risingTide 添加&lt;any&gt; 会删除类型检查,因此不会出现 TypeScript 编译时错误(编辑器中也不会出现错误)。但是 TypeSciprt 最终会被编译成每个方法都是公开的 Javascript,因此这将有助于消除 Typescript 错误。【参考方案9】:

如果您想在一个类中测试私有函数,为什么不向您的类添加一个构造函数来指示这些私有函数被返回?

请仔细阅读以了解我的意思:http://iainjmitchell.com/blog/?p=255

我一直在使用类似的想法,到目前为止效果很好!

【讨论】:

如果你发布了你的私有方法,它就不再是私有了。顺便说一句,正如我在回答中所描述的,测试 privat 方法没有多大意义。 我们可以同意是不同意的。我们的 javascript 代码库非常庞大,我们只在某些类上公开了一些公共函数/属性。在这些私有函数中处理了很多逻辑。我只公开了一个私有方法,因此测试框架可以访问它。如果没有正确调用构造函数,则不会返回私有函数。【参考方案10】:

没有因为您无法访问实例上下文之外的私有函数。

顺便说一句,监视您要测试的对象不是一个好主意。当您测试是否调用了您要测试的类中的特定方法时,它什么也没说。假设您编写了测试并通过了测试,两周后您重构了函数中的一些内容并添加了一个错误。所以你的测试仍然是绿色的,因为你调用了这个函数。乙

当您使用Dependency Injection 时,间谍很有用,其中所有外部依赖项都由构造函数传递,而不是在您的类中创建。因此,假设您有一个需要 dom 元素的类。通常,您将在类中使用 jquery 选择器来获取此元素。但是您想如何测试是否使用该元素完成了某些操作?当然,您可以将其添加到您的测试页面 html 中。但是您也可以在构造函数中调用传递元素的类。这样做,您可以使用 spy 来检查您的类是否按预期与该元素交互。

【讨论】:

说“监视你想测试的对象不是一个好主意”是不正确的。间谍的使用不仅限于检查一个函数是否被简单地调用,仅此而已。您可以使用间谍检查返回值,完全替换测试用例的函数,抛出错误等。我建议阅读 jasmine 文档以获得更完整的理解。 窥探不是个好主意!??你不能再错了!是的,我同意蒂姆的观点,你应该看看 doco,谁投了这个票?! 我不是这么说的。可以使用间谍。但是您应该将要测试的对象作为黑匣子处理。只测试进出的东西。不要测试黑匣子的内部,如果你监视被测对象的方法,你会怎么做。所以监视你传递给对象的回调是完全没问题的。 恰恰相反。您正在测试“单元”,您对其他“单元”在做什么不感兴趣。您将对其他“单元”进行测试。

以上是关于在私有方法上使用 Jasmine spyon的主要内容,如果未能解决你的问题,请参考以下文章

如何使用Jasmine Unit测试测试私有方法

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

使用 Jasmine 监视私有变量的属性/函数

使用 Jasmine 对包含私有超时的单元测试 Angularjs 指令

使用jasmine.SpyObj-Angular / Jasmine测试服务属性上的可观察对象

使用 Jasmine 监视 Backbone.js 路由调用