Mocking a javascript method with ScrewUnit - javascript

I have a simple validation method as follows
function someMethod {
//some processing
}
I want to unit test this method. What is the simplest way I can mock it. Usually if I have an object as follows:
var someObject = function() {
reload : function() {
//reload logic here
}
}
I can stub someObject and then check if mock(someObject).should_receive("reload").exactly('once')
or something like that. But since this time I just have a method. How do I mock that?

Mocking of code that is non-object oriented is difficult. Misko Hevery wrote about it here: http://misko.hevery.com/2008/12/15/static-methods-are-death-to-testability. The predicament is lack of a "hook" through which mocking stuff can be injected into the computation.
You can have the actual impl. of the method reside in an object. The method will simply delegate to that object. Thus, in order to test the method you only need to test the object (making the reasonable assumption that you got the delegation code right).

Related

Angular Unit Test, SpyOn stand-alone function

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!

Factory method reference confusion, and guideline to code it

I have following angular service.
(function () {
"use strict";
angular.module("theModule")
.factory("theService", theServiceFactory);
function theServiceFactory() {
return {
theFn: theFn,
theFailureFn: theFailureFn,
theSuccessFn: theSuccessFn
};
function theFn() {
angular.noop();
}
function theFailureFn() {
theFn();
}
function theSuccessFn() {
this.theFn();
}
}
}());
Functions are defined separately and their references are assigned to object being returned by the factory.
And I have following jasmine test cases.
describe("The Service Test Specifications", function () {
var theService;
beforeEach(module('theModule'));
beforeEach(inject(function(_theService_) {
theService = _theService_;
}));
it("should call 'theFn' from 'theFailureFn'", function () {
spyOn(theService, "theFn");
theService.theFailureFn();
expect(theService.theFn).toHaveBeenCalled();
});
it("should call 'theFn' from 'theSuccessFn'", function () {
spyOn(theService, "theFn");
theService.theSuccessFn();
expect(theService.theFn).toHaveBeenCalled();
});
});
Test Case should call 'theFn' from 'theFailure' is being failed whereas should call 'theFn' from 'theSuccess' is being passed.
From source code it seems object's theFn is referring to function theFn but actually it's not. It is causing first test case to fail. (Q1) At what stage different reference is assigned to object's theFn?
Second test case is passing as theFn is invoked with this inside theSuccess. But using this in that situation is strict mode violation. I like and follow John Papa's style guide so I created factory and defined all functions below it. (Q2) What would be the better way to write such function?
(Q3) If theFailure is written correctly, is there any way to detect in test case that function theFn is called?
Plunkr: http://plnkr.co/edit/PsQTZQlIgWI3OTMaYi7n
It is actually calling theFn() from theFailureFn(), and NOT calling theFn() from the sucesssFn(). It's the opposite result of your test.
As you see from this,
http://plnkr.co/edit/Tp5FtsL8DAjkcPO0m0ZV?p=preview
console.log('theService.theFn BEFORE spyOn', theService.theFn);
spyOn(theService, "theFn");
console.log('theService.theFn AFTER spyOn', theService.theFn);
Result
theService.theFn BEFORE spyOn theFn()
theService.theFn AFTER spyOn j$.createSpy.spy()
your Jasmine spyOn(theService, "theFn"); is setting an instance of theService, this.theFn, and your test is checking this.theFn is called or not. Remember that theService is a Hash, not a function.
As you see from the output of this line;
console.log('caller theFailureFn', this, theFn, this.theFn)
//OUTPUT
caller theFailureFn Object {} theFn() j$.createSpy.spy()
theFn and this.theFn is very different. theFn is an object property value and this.theFn is an instance of object, Hash.
To answer your question,
(Q1) At what stage different reference is assigned to object's theFn
theFn is assigned as you expected. spyOn makkes difference in your case.
(Q2) What would be the better way to write such function?
To test a function calls a function of an object, it should return a function, not a hash.
(Q3) If theFailure is written correctly, is there any way to detect in test case that function theFn is called?
The same answer as Q2.
Dont use this in .factory(). Factory is just executed as function and it just returns what you explicitly specify as return object. Angular uses .service() as a constructor function which is executed with new operator and thats the place where you will use this.
That means that your theFailureFn() is written correctly.
As for Q3, it may fail just because how spyOn is implemented.
Edit:
As i supposed, its the implementation of spyOn().
spyOn wraps the function but in your factory you are still referencing the original function. Try to use expect(this.theFn).toHaveBeenCalled();

Ember.observer run on init

I'm attempting to build an Ember app without prototype extensions and the Ember docs give examples of how to do this, but they don't include the example of when I want my observer to run on init.
So currently if my code were written like this:
fullNameChanged: function() {
// deal with the change
}.observes('fullName').on('init')
The only example I can find to write it is like this:
Person.reopen({
fullNameChanged: Ember.observer('fullName', function() {
// deal with the change
})
});
So how would I tell this code to run on init?
May be you are looking for this
Person.reopen({
fullNameChanged: Ember.on('init', Ember.observer('fullName', function () {
// deal with the change
}))
});
OR (this won't fire handler if change happens on init, use above on that case)
Person.reopen({
init: function(){
Ember.observer('fullName', function() {
// deal with the change
});
}
});
Alright, this edit for answer the mistakes(?) mentioned below
Well, sometimes it might be necessary to fire the observer on initialization time.
Ember.observer is an Ember namespace method, not part of Ember.Object's prototype. Therefore this.observer never exists, but addObserver() does.
There is no need to invoke the handler, Ember runtime will invoke the handler when the property changes
calling this._super is unnecessary unless it really does matter. In this case, if Person just extends Ember.Object calling super doesn't do anything.
By default, does nothing unless it is overridden during class definition.
It's contextual, and as long as OP didn't specify anything about class definition it's beyond the scope of answering.
Nothing better explains than an example
The accepted answer actually contains five separate mistakes, of varying degrees of severity.
It unnecessarily places setting up the observer in the init hook.
It sets up the observer inside the init hook incorrectly, using Ember.observer instead of this.observer, which won't even work.
It fails to invoke (as opposed to setting up) the handler at init time.
It fails to call init on the superclass.
It unnecessarily uses reopen.
1. No need to set up observer in init hook
You do not need any procedural "call" or "invocation" in an init hook to set up an observer. Either of the two following forms will set them up automatically when the object is instantiated.
fullNameChanged: function() { } . observes('fullName')
observeFullNameChanged: Ember.observer('fullName', this.fullNameChanged.bind(this))
2. Use object.observer for procedural setup of observers.
If you did want to set up the observer procedurally, then you call object.observer, not Ember.observer, which is defined for use as above. Calling Ember.observer procedurally will accomplish nothing; Ember will have no idea of what object the property to observe lies. In this case, it would be this.observer('fullName', ...) (although as mentioned above you actually don't need to do this at all; instead use the approach of point 1).
3. Invoke handler on init
But you also want to invoke the handler at init time. There are three ways:
init: function() { this.fullNameChanged(); /* call super */ }
initFullNameChanged: Ember.on('init', this.fullNameChanged.bind(this))
fullNameChanged: function() { ... }.on('init')
where the third option uses the prototype extensions you don't want.
4. Calling super from init
If you are going to have an init hook, even though it's not needed, you need to call super, or things will break down horribly:
init: function() {
...
this._super.apply(this, arguments);
}
5 No need for reopen
reopen accomplishes nothing here. Just put the above properties into the class definition itself.
Solution
The correct answer to what is the equivalent of
fullNameChanged: function observer() { }.observes('fullName').on('init')
is therefore
fullNameChanged: function() { },
observeFullNameChanged: Ember.observer('fullName', this.fullNameChanged.bind(this)),
initFullNameChanged: Ember.on('init', this.fullNameChanged.bind(this))
It would be equivalent, and possibly more readable, to do this:
initFullNameChanged: Ember.on('init', function() {
// define and execute handler
(function fullNameChanged() { ... }());
// set up obsever
this.observe('fullName, fullNameChanged);
})

Calling helper functions from within template.rendered in Meteor.js, error in 1.0, fine in 0.9.3

In an effort to avoid repeating code I found it useful to have helper functions that could be called from within a foo.rendered function (for instance). Why is this possible in 0.9.3 of Meteor, but throws an error in 1.0 ?
Template.foo.helpers({
'fooFn' : function(){
return "something"
}
});
Template.foo.rendered = function(){
var something = Template.foo.fooFn();
}
Should I change the syntax in foo.rendered (am I calling it wrong?) or maybe use a different approach entirely (set up functions outside of the helpers({}) and rendered() and call those? or set this up as a registered helper function?
It looks like it is possible as of Meteor 1.0.3.1 to find and call helper functions, although it is clear it's not supposed to be used like this.
Still it can be done:
Template.foo.__helpers[" fooFn"]()
Please notice the leading space for the function name.
The other way of dealing with this is attaching a function to a global namespace, then calling that from somewhere else in your code, as user3557327 mentioned.
Additionally you can use:
Template.registerHelper('myHelper', function (){return 'Look At Me!'})
to register a global helper, and call it explicitly using:
UI._globalHelpers['myHelper']()
I think this would be a better method: How to use Meteor methods inside of a template helper
Define a function and attach it to the template. Call that function from rendered, as well as your template helper. Like MrMowgli said, you probably aren't "supposed" to call template helpers from within the .js file, only from the ...that could probably break in the future.
For example define a function and attach it to the tamplate:
Template.Play.randomScenario = function () { // HACK HACK HACK }
and then call it from your lifecycle method
Template.Play.created = function () {
Template.Play.randomScenario();
};
scenario: function () {
return Template.Play.randomScenario();;
},
I had the same problem and this is the solution I used. Hope that helps.

Good approach to using test spies with dynamic function binding

I'm using $.proxy(this, 'methodName') to use methods of my object as event handlers for DOM events.
When it comes to testing I'd like to use Jasmine's spyOn to monitor whether the callbacks get fired. However as the listener is attached within my Object's constructor by the time I get to spying on the method it's too late, and the raw, unspied function has already been used by $.proxy.
What are good approaches to tackling this? One thing I've considered is spying on the prototype's methods directly, but I'm worried about the impact this might have on each test being independent of others. Another would be to change how I attach the listeners in my code, but this seems like throwing out the baby with the bathwater.
You can spy on the prototype of object before the test starts. So it will not have any impact of your other tests.
var function A {
$.proxy(this, 'methodName');
}
a.prototype.methodName = function() {
console.log('test');
}
describe('…', function() {
var a;
before(function() {
jasmine.spyOn(a.prototype, 'methodName');
a = new A();
});
it('should…', function() {
});
});

Categories

Resources