在私人方法上使用茉莉花


76

是否可以在类私有方法上使用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();
    });
});

Answers:


135

只需将通用参数<any>添加到spyon()函数:

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

它工作完美!


3
我尝试了这种解决方案,并且效果很好。另外,可以像前面提到的那样,使用数组索引符号访问私有字段。
Koji D'infinte

7
这些都不适合我。由于spyOn带有两个参数,因此无法通过数组表示法进行访问。如图所示放入<any>也会引发错误的参数数量错误。这对我spyOn(fakePerson as any, 'sayHello');
Russ

2
我也这样做。有没有更好的方法而不会被任何人如此“通用”?我尝试了例如spyOn <fakePerson>(fakePerson,'sayHello'); 但随后仍然抱怨“打招呼”。是否可能像spyOn <fakePerson> <fuction>之类的东西?对于更好的上下文?
L1ghtk3ira

2
有人还能解释为什么该解决方案有效吗?加法到底能起到<any>什么作用?
上升潮

11
@risingTide Adding<any>删除类型检查,因此不会出现TypeScript编译时错误(并且在您的编辑器中也没有错误)。但是TypeSciprt最终会被编译成Javascript,其中每个方法都是公共的,因此这将有助于消除Typescript错误。
WindUpDurb

13

可以说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

@JeffryHouser这sayHello是一个私有方法。第一行是如何在其上创建间谍。第二行是测试。
A-Sharabiani

得到它了; 您的答案缺少有关如何监视私有方法(也就是使用<any>标签)的解释。这就是为什么我感到困惑。
JeffryHouser

13
spyOn<any>(fakePerson, 'sayHello');
expect(fakePerson['sayHello']).toHaveBeenCalled();

通过添加<any>到spyOn,可以将其从打字稿类型检查中删除。您还需要使用数组索引符号以便在测试期望中访问私有方法(sayHello)


尽管此代码可以回答问题,但提供有关如何和/或为什么解决问题的其他上下文将提高​​答案的长期价值。
伊戈尔·F

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

4
如果尝试调用非导出的(私有)函数Error:(33, 56) TS2345:Argument of type '"sayHello"' is not assignable to parameter of type '"sayGoodbye"'.sayGoodbye则会收到类型错误:其中有一个公共方法,Person并且sayGoodbye是私有方法。我必须将其投放给任何(“ sayHello”为其他)
FlavorScape

我在这里需要更多上下文,看来您的分配无法正常工作,并且无法访问私有功能。但是,尝试像这样访问它:person["sayHello"]而不是person.sayHello(如果您正在这样做)。这不是最佳做法,但是在极少数情况下是可以原谅的;)
jurl

同意@FlavorScape。Typescript(至少为1.7及更高版本)期望监视的功能是公共的,并且由于sayHello不是类型sayGoodbye(或任何其他公共功能),它将引发错误。我只能使用上面列出的spy <any>修复此问题。
Beartums

自从我上次发表评论以来,情况似乎发生了变化。spy<any>可能确实是正确的答案。谢谢
jurl

3

没理由,您不能在实例上下文之外访问私有函数。

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

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


28
说“监视想要测试的对象不是一个好主意”是不正确的。间谍的使用不仅限于检查是否只是简单地调用了函数而已。您可以使用间谍来检查返回的值,完全替换测试用例的功能,引发错误等。我建议阅读茉莉花文档,以更全面地理解。
Tim McClure 2015年

2
间谍不是一个好主意!你不能再错了!是的,我同意蒂姆的观点,你应该看一下doco,谁投票赞成?
AltF4_

3
那不是我说的。可以使用间谍。但是您应该将要测试的对象作为黑匣子来处理。只测试进出的东西。不要测试黑匣子的内部结构,如果您监视被测对象的方法,该怎么办。因此,监视传入您的对象的回调是完全可以的。
AndreasKöberle'17

3

就我而言(打字稿):

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

或模拟结果:

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

2

Typescript被编译为javascript,在javascript中,每种方法都是公共的。因此,您可以使用数组索引符号来访问私有方法或文件,即:

Object['private_field']

不幸的是,博客链接已死。
geisterfurz007

1
在这里被否决,部分用于死掉的博客链接;部分原因是我们无法使用对象数组表示法来设置间谍。
JeffryHouser

0

如果要在一个类中测试私有函数,为什么不向您的类添加一个构造函数,以表明这些私有函数已返回?

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

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


5
如果发布私有方法,则不再是私有方法。顺便说一句,正如我在回答中所述,测试privat方法没有多大意义。
AndreasKöberle,

1
我们可以同意这一点。我们的javascript代码库很大,我们只在某些类上公开了一些公共函数/属性。这些专用功能处理了很多逻辑。我只公开一个私有方法,因此测试框架可以访问它。如果未正确调用构造函数,则不会返回私有函数。
StevenMcD 2011年

0
const spy = spyOn<any>(component, 'privateMethod');
expect(spy).toHaveBeenCalled();

为避免有关通过字符串文字访问对象的棉绒警告,请创建间谍对象的局部常量。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.