using Jasmines spyon upon a private method
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;
});
user502014
Updated on October 13, 2021Comments
-
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 over 12 yearsIf 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 over 12 yearsWe 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 almost 9 yearsIt'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_ over 7 yearsits 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 over 7 yearsThats 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 about 7 yearsI 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"'.
wheresayGoodbye
is a public method onPerson
andsayGoodbye
is private. I have to cast it to any ("sayHello" as any) -
jurl about 7 yearsI 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 ofperson.sayHello
(if that's what you are doing). This is not best practice, but in rare cases is forgiven ;) -
Samuel Thompson about 6 yearsThis should be the correct answer. This is what I do all the time.
-
Beartums about 6 yearsAgreed 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 about 6 yearsIt seems like things have changed since my last comment.
spy<any>
may indeed be the right answer. Thanks -
Koji D'infinte about 6 yearsI 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 about 6 yearsNeither 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 over 5 yearsI 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 over 5 yearsCan someone also explain why this solution works? What exactly does adding
<any>
do so that this works? -
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 over 5 years@WindUpDurb Gotcha...that makes sense. Thank you.
-
geisterfurz007 almost 5 yearsThe blog link is dead unfortunately.
-
JeffryHouser over 4 yearsDown 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 over 4 yearsDown 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 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 over 4 yearsGot 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. over 4 yearsWhile 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 over 3 years
spy<any>
is a revelation. -
Slaven Tomac about 3 yearsIt'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 about 2 yearsDoes not compile with react, so better use the
as
type cast instead.