using Jasmines spyon upon a private method

80,318

Solution 1

Just add a generic parameter < any> to the spyon() function:

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

It works on perfectly !

Solution 2

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

by adding <any> to spyOn you remove it from typescript type check. you also need to use array index notation in order to access a private method (sayHello) in the test expect

Solution 3

Let say sayHello(text: string) is a private method. You can use the following code:

// 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');
  • Create a spy on private method using any.
  • To access the private (or protected) method use [] operator.

Solution 4

if you use Typescript for your objects, the function isn't really private.
All you need is to save the value that returned from spyOn call and then query it's calls property.

At the end this code should work fine for you (at least it worked for me):

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

Solution 5

In my case (Typescript):

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

OR with mocked result:

jest.spyOn<any, string>(authService, 'isTokenActual').mockImplementation(() => {
  return false;
});
Share:
80,318
user502014
Author by

user502014

Updated on October 13, 2021

Comments

  • user502014
    user502014 over 2 years

    is it possible to use Jasmine unit testing framework's spyon method upon a classes private methods?

    The documentation gives this example but can this be flexivble for a private function?

    describe("Person", function() {
        it("calls the sayHello() function", function() {
            var fakePerson = new Person();
            spyOn(fakePerson, "sayHello");
            fakePerson.helloSomeone("world");
            expect(fakePerson.sayHello).toHaveBeenCalled();
        });
    });
    
  • Andreas Köberle
    Andreas Köberle over 12 years
    If you publish your privat method it's not privat anymore. Btw, as I described in my answer it make not much sense to test privat method.
  • StevenMcD
    StevenMcD over 12 years
    We can agree is disagree on that. Our javascript codebase is massive and we only expose a handleful of public functions/properties on some of our classes. A lot of logic is handled in those private functions. I only public a private method so the testing framework has access to it. If the constructor is not called correctly then the private function is not returned.
  • Tim McClure
    Tim McClure almost 9 years
    It's not correct to say 'its not a good idea to spy on objects you wanna test`. Use of spies is not limited to checking whether not a function was simply called and that's it. You can use spies to check returned values, to replace functions entirely for test cases, throwing errors, etc. I would suggest reading the jasmine documentation for a more complete understanding.
  • AltF4_
    AltF4_ over 7 years
    its not a good idea to spy !?? you cant be more wrong! yeap i agree with Tim and you should look at the doco, whos voted this up?!
  • Andreas Köberle
    Andreas Köberle over 7 years
    Thats not what I said. Its ok to use spies. But you should handle the object you wanna test as a black box. Only test what goes in and out. Don't test internals of the black box, what you would do if you spy on methods of the object under test. So spy on on callbacks that you pass into the object is totally fine.
  • FlavorScape
    FlavorScape about 7 years
    I get a type error if I try to call a non-exported (private) function: Error:(33, 56) TS2345:Argument of type '"sayHello"' is not assignable to parameter of type '"sayGoodbye"'. where sayGoodbye is a public method on Person and sayGoodbye is private. I have to cast it to any ("sayHello" as any)
  • jurl
    jurl about 7 years
    I need more context here, it seems like your assignment is not working and not the access to the private function. But try to access it like this: person["sayHello"] instead of person.sayHello (if that's what you are doing). This is not best practice, but in rare cases is forgiven ;)
  • Samuel Thompson
    Samuel Thompson about 6 years
    This should be the correct answer. This is what I do all the time.
  • Beartums
    Beartums about 6 years
    Agreed with @FlavorScape. Typescript (at least 1.7 and up) expects the spied-on finction to be public, and since sayHello is not type sayGoodbye (or any of the other public functions) it will throw an error. I've only been able to fix this using the spy<any> listed above.
  • jurl
    jurl about 6 years
    It seems like things have changed since my last comment. spy<any> may indeed be the right answer. Thanks
  • Koji D'infinte
    Koji D'infinte about 6 years
    I tried this solution and it works perfectly well. Additionally, a private field can be accessed using array index notation, like I mentioned earlier on.
  • Russ
    Russ about 6 years
    Neither of those worked for me. You can't access via array notation since the spyOn takes two arguments. Putting <any> as shown also throws an error of the wrong number of arguments. This is what worked for me: spyOn(fakePerson as any, 'sayHello');
  • L1ghtk3ira
    L1ghtk3ira over 5 years
    I do this as well. Is there a better way without being so 'generic' using any? I tried for example spyOn<fakePerson>(fakePerson, 'sayHello'); But then still complains about 'say hello'. IS it possible something like spyOn<fakePerson><fuction> or something? For a bit better context?
  • risingTide
    risingTide over 5 years
    Can someone also explain why this solution works? What exactly does adding <any> do so that this works?
  • WindUpDurb
    WindUpDurb over 5 years
    @risingTide Adding <any> drops the type checking, so there'll be no TypeScript compile-time errors (and no errors in your editor). But the TypeSciprt ultimately gets compiled into Javascript where every method is public, so this will work to drop the Typescript errors.
  • risingTide
    risingTide over 5 years
    @WindUpDurb Gotcha...that makes sense. Thank you.
  • geisterfurz007
    geisterfurz007 almost 5 years
    The blog link is dead unfortunately.
  • JeffryHouser
    JeffryHouser over 4 years
    Down voted because you didn't address the main concern which is how do you spy on a private method. This code is not all that different than what was originally provided in the question.
  • JeffryHouser
    JeffryHouser over 4 years
    Down voted here, part for the dead blog link; part for the fact that we cannot use object array notation to set up a spy.
  • A-Sharabiani
    A-Sharabiani over 4 years
    @JeffryHouser The sayHello is the a private method. and the first line is how to create a spy on it. The second line is the test.
  • JeffryHouser
    JeffryHouser over 4 years
    Got it; your answer is missing the explanation of how to spy on a private method--AKA using the <any> tag. That is why I got confused.
  • Igor F.
    Igor F. over 4 years
    While this code may answer the question, providing additional context regarding how and/or why it solves the problem would improve the answer's long-term value.
  • Neurotransmitter
    Neurotransmitter over 3 years
    spy<any> is a revelation.
  • Slaven Tomac
    Slaven Tomac about 3 years
    It's exactly the opposite. You are testing "unit", you are not interested what other "unit" is doing. You will have test for other "unit".
  • Mike Lischke
    Mike Lischke about 2 years
    Does not compile with react, so better use the as type cast instead.