using Jasmines spyon upon a private method

JavascriptUnit TestingJasmine

Javascript Problem Overview


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

Javascript Solutions


Solution 1 - Javascript

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

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

It works on perfectly !

Solution 2 - Javascript

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 - Javascript

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 - Javascript

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 - Javascript

In my case (Typescript):

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

OR with mocked result:

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

Solution 6 - Javascript

spyOn(fakePerson, <never>'sayHello');
spyOn(fakePerson, <keyof Person>'sayHello');

Both silence the type error and don't interfere with TSLint's no-any rule.

Solution 7 - Javascript

Typescript gets compiled to javascript and in javascript every method is public. So you can use array index notation to access private methods or fileds, viz:

Object['private_field']

Solution 8 - Javascript

If you want to test private functions within a class, why not add a constructor to your class that signals that those private functions get returned?

Have a read through this to see what I mean: http://iainjmitchell.com/blog/?p=255

I have been using a similar idea and so far its working out great!

Solution 9 - Javascript

No cause you cant access a private function outside the context of your instance.

Btw, its not a good idea to spy on objects you wanna test. When you test if a specific method in your class you want to test is called, it says nothing. Lets say you wrote the test and it passed, two weeks later you refactor some stuff in the function and add a bug. So your test is still green cause you the function called. B

Spies are useful when you work with Dependency Injection, where all external dependencies are passed by the constructor and not created in your class. So lets say you have a class that needs a dom element. Normaly you would use a jquery selector in the class to get this element. But how you wanna test that something is done with that element? Sure you can add it to your tests pages html. But you can also call your class passing the element in the constructor. Doing so, you can use spy to check if your class interacts with that element as you expected.

Solution 10 - Javascript

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

To avoid lint warnings regarding object access via string literals, create a local constant of the spy object.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questionuser502014View Question on Stackoverflow
Solution 1 - JavascriptLuillyfeView Answer on Stackoverflow
Solution 2 - JavascriptomerView Answer on Stackoverflow
Solution 3 - JavascriptA-SharabianiView Answer on Stackoverflow
Solution 4 - JavascriptjurlView Answer on Stackoverflow
Solution 5 - Javascriptuser3765649View Answer on Stackoverflow
Solution 6 - JavascriptmlntdrvView Answer on Stackoverflow
Solution 7 - JavascriptKoji D'infinteView Answer on Stackoverflow
Solution 8 - JavascriptStevenMcDView Answer on Stackoverflow
Solution 9 - JavascriptAndreas KöberleView Answer on Stackoverflow
Solution 10 - JavascriptOOPView Answer on Stackoverflow