![](/style/images/good.png)
![](/style/images/bad.png)
Unit Testing Using Jasmine Spies
source link: https://keyholesoftware.com/2021/12/13/unit-testing-using-jasmine-spies/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
A Jasmine spy can stub any function and track all calls to that function and all of its arguments. Jasmine Spies are a powerful tool to use in unit testing because they allow us to focus on the function that is being tested.
A spy will only exist in the describe
or it
block that it is defined. For this reason, when working on these tests, we will be using describe
blocks per function that is being tested.
Let’s take a look at the Jasmine Spies I use most often when writing unit tests.
and.callThrough
Spy
The first spy we will look at is the and.callThrough
spy. This spy will track calls to the function it is spying on, but it will also pass through to the function and allow it to run. This means that when we use this spy, the function being spied on will still do what it is written to do, but we can track the calls to it. Look at the following example.
var stuff = []; var thing = { addThing: function(value) { stuff.push(value); } };
Now let’s install an and.callThrough
spy for the addThing
function of thing
.
spyOn(thing, 'addThing').and.callThrough();
For all the spies in this article, we will be using spyOn(obj, methodName)
to install our spies. For the spy on addThing
we are saying that we want to install a spy on thing
and that we are replacing the method with the method name addThing
.
Now that the and.callThrough
spy is installed, let’s look at what we can do with it by looking at some expect statements
.
toHaveBeenCalled
Matcher
If all we want to know is that our function that is being spied on has been called, toHaveBeenCalled
is what we are looking for. The following expect
just tests that our spy has been called, not caring about parameters, how many times it may have been called, or anything else.
thing.addThing('thing1'); expect(thing.addThing).toHaveBeenCalled();
When thing.addThing
is called, the spy will register that it was called and this can now be used by the expect
. The function will still do what it was going to do, so if we displayed the contents of stuff
it would be ['thing1']
.
toHaveBeenCalledTimes
Matcher
To test that a function has been called the appropriate amount of times, use the toHaveBeenCalledTimes
matcher.
spyOn(thing, 'addThing').and.callThrough(); thing.addThing('thing1'); thing.addThing('thing2'); expect(thing.addThing).toHaveBeenCalledTimes(2);
Because the spy is still and.callThrough
, thing1 and thing2 will be added to stuff
.
and.callFake
Spy
Now let’s look at the and.callFake
spy. This spy will track all calls to the defined function, but with this, we can pass in a new function that will be called in place of the original.
var calc = { add: function(x, y) { return x + y; } } spyOn(calc, 'add').and.callFake((x, y) => {return x + y + x}); expect(calc.add(2, 1)).toEqual(5); expect(calc.add).toHaveBeenCalled();
and.callFake
shines in its ability to allow you to define what a function call does depending on the describe
or it
block it is in. This spy is also very handy when a quick mock of a function is needed.
and.returnValue
Spy
The and.returnValue
spy is probably the one I have used most often. Just like the other spies, it will track the calls to the function, but instead of calling the function, you can specify a value to return. This can make setting up your test scenarios much easier.
var calc = { twoPlusTwo: function() { return 4; } }; spyOn(calc, 'twoPlusTwo').and.returnValue(5); expect(calc.twoPlusTwo()).toEqual(5);
and.throwError
Spy
The last Jasmine Spy we will look at is the and.throwError
spy. With this spy, every call will throw an error with the specified value.
var stuff = []; var thing = { addThing: function(value) { stuff.push(value); } }; spyOn(thing, 'addThing').and.throwError('ERROR'); expect(function() { thing.addThing('thing1') }).toThrowError('ERROR'); expect(function() { thing.addThing('thing2') }).toThrowError('ERROR'); expect(thing.addThing).toHaveBeenCalledTimes(2);
Using the and.throwError
spy gives us an easy and clean way to have our tests throw an error, so we can make sure to test that our error functionality is also working as intended.
Conclusion
Unit testing is an important part of the development process. It gives us the ability to know that our code is working as intended and can also let us know if we may have broken something that we didn’t even think of.
With the help of Jasmine Spies, we can make our test setup easier, and we can give ourselves more options for what we can test against. Hopefully, this will give you a good starting point for all your Jasmine spying needs!
In case it would be helpful, I’ve attached my GitHub Repository. Take a look!
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK