Testing controllers - aca-mobile/ti-unit GitHub Wiki
The question arises: "Should we really test controllers?". This depends. How much logic do we want inside a controller? And if there is only 'glue' code inside a controller, why should we unit test them? Is there still a valid reason? I guess not, though it depends case by case.
But if we do, we need to keep following points in mind:
- add a modules.exports.test block which exports the test functions
Example controller:
var UserManager = require('user.manager');
function _onAuthSuccess() {
Alloy.Globals.loading.hide();
UserManager.setUserName($.username.getValue());
Alloy.createController('dealers').getView().open();
$.authenticate.close();
}
function _onAuthLoginError() {
Alloy.Globals.loading.hide();
Alloy.Globals.notifications.showError(L('authenticate.error.authentication.failure'));
}
function _onAuthTokenValidationFailure() {
Alloy.Globals.loading.hide();
}
module.exports.test: {
_onAuthSuccess: _onAuthSuccess,
_onAuthLoginError: _onAuthLoginError
}
It is of the utmost importance to export the test functions on modules.exports.test, otherwise these exports will cause the application to fail (due to how Alloy code is post-processed) upon (2nd) controller instantiation. Example controller test:
describe('authenticate test', function() {
var USER_NAME = "John Doe";
var userManagerMock = {
setUserName: function(){},
getUserName: function(){}
};
var dealerControllerMock = {
getView: function(){}
};
var dealerViewMock = {
open: function(){}
}
Ti = require('tiunit/jsca.api.parser').parseFromConfig();
MockRequire = require('tiunit/mockrequire');
Alloy = {
CFG: {
throttleTimeOut: 100
},
Globals: {
loading: {
hide: function(){}
},
vabfsNetworkClient: {
hasAutoLogin: function(){}
},
notifications: {
showError: function(){}
}
},
createController: function(){}
};
var controllerUnderTest; // class under test
L = function(s){
return s;
};
beforeEach(function () {
$ = require('tiunit/mockcontroller').createControllerMock('../app/controllers/authenticate');
MockRequire.addMock('user.manager', userManagerMock);
controllerUnderTest = require('../app/controllers/authenticate');
});
afterEach(function(){
MockRequire.resetMocks();
});
it('should create dealers controller when authentication was succesful', function(){
spyOn(userManagerMock, 'setUserName');
spyOn(Alloy.Globals.loading, 'hide');
spyOn(Alloy, 'createController').and.returnValue(dealerControllerMock);
spyOn(dealerControllerMock, 'getView').and.returnValue(dealerViewMock);
spyOn($.username, 'getValue').and.returnValue(USER_NAME);
spyOn($.authenticate, 'close');
controllerUnderTest.test._onAuthSuccess();
expect(Alloy.Globals.loading.hide).toHaveBeenCalled();
expect(userManagerMock.setUserName).toHaveBeenCalledWith(USER_NAME);
expect(Alloy.createController).toHaveBeenCalledWith('dealers');
expect(dealerControllerMock.getView).toHaveBeenCalled();
expect($.authenticate.close).toHaveBeenCalled();
});
it('should show error message when a login error has occured', function(){
spyOn(Alloy.Globals.loading, 'hide');
spyOn(Alloy.Globals.notifications, 'showError');
controllerUnderTest.test._onAuthLoginError();
expect(Alloy.Globals.loading.hide).toHaveBeenCalled();
expect(Alloy.Globals.notifications.showError).toHaveBeenCalledWith('authenticate.error.authentication.failure');
});
});