.factory('Tag', function($window) {
var Context = {};
function reset() {
return Context !== {} ? Context : {};
}
return{
reset:reset
};
})
I have done testing like this
describe('method: reset()', function(){
it('should reset the Context variable', function(){
spyOn(Tag, 'reset').andCallFake(function(){
return Context;
});
expect(Context).toEqual({});
});
afterEach(function(){
if(Context!== {}){
Context = {};
}
})
});
Is, this test is accurate, if yes then why my test coverage is not increasing..
you are calling a fake function not the real one, so the code in your actual function is never executed.
your code coverage tool only marks code that was actually hit.
andCallFake is used to mock an external function which you are not interested in testing and you just want some mock response when the code you are actually testing calls it.
your code should make a real call to ...
Tag.reset()
now if Tag.reset() makes a call to code in another service which you do not want to test then you can use callFake on that call.
Remember this is "unit" testing. The "unit" of code you want to test is the code inside your service, not outside of your service.
Related
I am using Jasmine to test an Angular app and would like to test that the getItem() function within my controller is called when the ready() function of the controller is called.
--- Controller ---
var vm = this;
vm.items = [];
$ionicPlatform.ready(ready);
function ready() {
vm.items.push(getItem());
function getItem(){
var item = //do stuff to get item;
console.log('getItem called');
return item;
}
}
--- Spec ---
describe('Controller', function(){
//--- Load app with dependencies and module to test code omitted.
beforeEach(function(){
//How do I spy on getItem() to test that it was called?
//I've tried getItem = jasmine.createSpy()
//I've tried spyOn(window, 'getItem')
}
//--- Initialize the controller and a mock scope code omitted.
beforeEach(function(done){
$ionicPlatform.ready(function(){
done();
});
});
it('getItem function should get called', function(){
expect(getItem).toHaveBeenCalled();
//--- Note, getItem does not get called according to the expect statement,
//--- but does output 'getItem called' to the terminal when running the test.
});
});
Unfortunately, you've come upon a fundamental limit of Javascript unit testing with Jasmine-- you can only spyOn methods that are exposed on some object. If there is a function that is internal to another function, and not exposed in anyway, you cannot test it directly.
However, you do have two options available to you:
Expose the function in a way that it can be spied on (generally as a method of whatever Angular component you are testing).
Test it indirectly.
The first is probably relatively self-evident, but the latter may be a little confusing. Basically, you can't test directly if the getItems function is called, but the function may have downstream methods it calls or values it changes you can test. For instance, you can test that vm.items.push is larger after ready is called, or you can spyOn(console.log) and expect(console.log).toHaveBeenCalledWith('getItem called').
You can find arguments for both approaches on the internet-- I tend to prefer approach two because I don't like doing refactors solely for the purpose of testability, but many will argue that refactoring for testability generally yields better code. That choice is yours to make. Hope this helps!
I have written a export module using protractor. it has multiple function defined inside it.
Now, I want to call one of the exported function inside another function within the same module.
My module looks like below.
module.exports = {
read_page_number_data: function {
// code here
},
read_page_data: function {
this.read_page_number_data().then(function () {
// Code here.
});
},
check_link_present: function {
// code here
},
click_link: function {
this.check_link_present().then(function () {
// Code here.
});
},
}
Now, when I call read_page_data function in my test script, I get below error.
Failed: this.read_page_number_data is not a function.
I have tried all the options given in below question. still there is no success.
protractor calling an exported function within the same module
NOTE: Before calling read_page_data function, I am calling click_link function, which internally calls check_link_present function. But this call works fine and check_link_present function gets call properly from click_link function. After this, control navigates to the page given in link.
One solution would be to assign the object to a variable specific to your module.
e.g.
module.exports = myModule = {
//...
}
Then you can call your functions within the module with myModule.read_page_number_data() etc.
You can find an example JSFiddle here.
Note on this context
One thing to keep in mind is that this can change it's context depending on how the parent function is called, which could be why it is working for click_link but not for read_page_data.
You can find more information on the this keyword here.
Why don't try like below. This is one of the best practices for Page Object Model test framework.
var PageName = function(){
this.firstMethod = function(){
//logic
};
this.secodnMethod = function(){
//logic
};
}
module.exports = new PageName();
I'm doing some unitTests and my scenario is the following. I have like 50 tests whose call to a service function must be the same, but for one single test It will be so helpfull if I can call the original method. I tried with the and.callThrough but It's not working correctly. I'm trying to override the spy too but I can't. What I'm doing wrong?
beforeEach(inject(function($controller, _myService_){
spyOn(_myService_, 'getSomeData').and.callFake(function(data, params){
return dummyData;
});
createController = function() {
return $controller('MyCtrl',{
$uibModalInstance: modalInstance,
myService: _myService_,
injectedData: injectedData
});
};
}));
This is my test case.
it('My test case', function(){
controller = createController();
controller.myService.getSomeData = jasmine.createSpy().and.callThrough()
});
I'm using jasmine 2.0 and that test case is continuously calling the callFake function.
thanks
jasmine.createSpy().and.callThrough() is unaware of the spied method and there's no way how it can know about it, calling it just results in calling a noop function.
Spying strategy can be changed for existing spies,
controller.myService.getSomeData.and.callThrough();
How can I define a Meteor method which is also callable in a template helper?
I have these two files:
file: lib/test.js
Meteor.methods({
viewTest : function (str) {
return str;
}
});
file: client/myView.js
Template.helloWorld.helpers({
txt : function () {
var str = Meteor.call('viewTest', 'Hello World.');
return str;
}
});
When I give "str" a normal string everything works fine. But in this case my template does not get any value. I defined - for the test - in the same file where the method is a normal function and tried to call the function. The error I got was that the function does not exist. So I think that Meteor tries to render the template before it knows anything about the methods I defined for it. But I think that this is a bit unusual - isn't it?
There is now a new way to do this (Meteor 0.9.3.1) which doesn't pollute the Session namespace
Template.helloWorld.helpers({
txt: function () {
return Template.instance().myAsyncValue.get();
}
});
Template.helloWorld.created = function (){
var self = this;
self.myAsyncValue = new ReactiveVar("Waiting for response from server...");
Meteor.call('getAsyncValue', function (err, asyncValue) {
if (err)
console.log(err);
else
self.myAsyncValue.set(asyncValue);
});
}
In the 'created' callback, you create a new instance of a ReactiveVariable (see docs) and attach it to the template instance.
You then call your method and when the callback fires, you attach the returned value to the reactive variable.
You can then set up your helper to return the value of the reactive variable (which is attached to the template instance now), and it will rerun when the method returns.
But note you'll have to add the reactive-var package for it to work
$ meteor add reactive-var
Sashko added a neat little package called meteor-reactive-method to solve this problem.
$ meteor add simple:reactive-method
Template.helloWorld.helpers({
txt: function() {
return ReactiveMethod.call('viewTest', 'Hello World.');
}
});
As I point out in common mistakes, helpers should be side-effect free, so I'd use this technique with caution. However, it's a really handy shortcut for cases where:
The helper should fire only once (it doesn't depend on reactive state).
The invoked method doesn't mutate the database.
You need to interface your return value with a Session variable as the request is asynchronous:
Template.helloWorld.helpers({
txt : function () {
return Session.get("txt") || "Loading";
}
});
Template.helloWorld.created = function() {
Meteor.call('viewTest', 'Hello World.', function(err, result) {
Session.set("txt", result);
});
}
So .rendered should be called once when your template loads (at least it should with the newer version of Meteor.)
The value would be called and displayed. Otherwise it would say "Loading".
Methods on the client side are asynchronous, and their return value is always undefined. To get the actual value returned by the method, you need to provide a callback:
Meteor.call('method', 'argument', function(error, result) {
....
});
Now, there's no easy way to use the result in your helper. However, you can store it in your template as a data object and then return it in the helper:
Template.template.created = function() {
var self = this;
self.data.elephantDep = new Deps.Dependency();
self.data.elephant = '';
Meteor.call('getElephant', 'greenOne', function(error, result) {
self.data.elephant = result;
self.data.elephantDep.changed();
});
};
Template.template.showElephant = function() {
this.elephantDep.depend();
return this.elephant;
};
This is expected behavior. You are not using methods as they are intended.
Your code defines a server method viewTest and a corresponding method stub on the client with the same name.
Meteor.call('viewTest', 'Hello World.'); remotely calls viewTest on the server and in parallel runs the stub on the client.
Regarding the return value of the stub please see the documentation here, in particular:
On the client, the return value of a stub is ignored. Stubs are run
for their side-effects: they are intended to simulate the result of
what the server's method will do, but without waiting for the round
trip delay.
Regarding the return value of the server method please see the documentation here, in particular:
On the client, if you do not pass a callback and you are not inside a
stub, call will return undefined, and you will have no way to get the
return value of the method. That is because the client doesn't have
fibers, so there is not actually any way it can block on the remote
execution of a method.
There is a fine little package for this by #msavin:
https://atmospherejs.com/msavin/fetcher
I've been reading through the Jasmine documentation and I've been struggling to understand what the Spies .and.stub method actually does. English is not my native language, so I don't even know what the word "stub" actually means, and there is no translation for it in my language.
In the documentation it says:
When a calling strategy is used for a spy, the original stubbing behavior can be returned at any time with and.stub.
describe("A spy", function() {
var foo, bar = null;
beforeEach(function() {
foo = {
setBar: function(value) {
bar = value;
}
};
spyOn(foo, 'setBar').and.callThrough();
});
it("can call through and then stub in the same spec", function() {
foo.setBar(123);
expect(bar).toEqual(123);
foo.setBar.and.stub();
bar = null;
foo.setBar(123);
expect(bar).toBe(null);
});
});
What does and.stub actually do and how is it useful?
For the term, you can look at wikipedia : http://en.wikipedia.org/wiki/Test_stub
In a nutshell it's a "fake" object that you can control that replaces a "real" object in your code.
For the function, what I understand is that and.stub() removes the effect of and.callThrough() on a spy.
When you call and.callThrough, the spy acts as a proxy, calling the real function, but passing through a spy object allowing you to add tests like expectation.
When you call and.stub, or if you never call and.callThrough, the spy won't call the real function. It's really usefull when you don't want to test an object's behavior, but be sure that it was called. Helping you to keep your test truly unitary.
To complete the previous answer:
Indeed, it's not clear from the doc, but it's very clear in the source code:
https://github.com/jasmine/jasmine/blob/4be20794827a63ca5295848c58ffc478624ee4dc/src/core/SpyStrategy.js
plan = function() {};
-> the called function is empty
this.callThrough = function() {
plan = originalFn;
-> the called function is the original function
this.stub = function(fn) {
plan = function() {};
-> the called function is empty (again)