admin管理员组

文章数量:1401835

I am doing unit testing using Karma and Jasmine. I have app.js as main source file:

app.service("someServ", function(){
  this.sendMsg = function(name){
    return "Hello " + name;
  }
})

app.factory("appFactory", function ($q, someServ) {
  function getData() {
    var defer = $q.defer();
    defer.resolve("Success message");
    return defer.promise;
} 

function foo(){
    var text = someServ.sendMsg("Message");
    alert(text);
}
return {
    getData : getData,
    foo : foo
}
})

app.controller("mainController",['$scope','$http','appFactory',function($scope, $http, appFactory){
var mct = this;
mct.printData = function(){
    var myPromise = appFactory.getData();
    myPromise
        .then(function(data){
            alert("Promise returned successfully. Data : " + data);
        }, function(error){
            alert("Something went wrong.... Error: "  + error);
        })
}
mct.showMsg = function(){
    appFactory.foo();
}
}]);

My testFile.js is as follows:

   beforeEach(module(function($provide){
    $provide.service("someServ", function(){
        this.sendMsg =   jasmine.createSpy('sendMsg').and.callFake(function(param){})
    });

    $provide.factory("appFactory", function(someServ, $q){
        function getData(){
            var defer = $q.defer();
            defer.resolve("Success message");
            return defer.promise;
        }
        function foo(){
            var facParam = "some text";
            someServ.sendMsg(facParam);
        }
        return {
            getData : getData,
            foo : foo
        }
    });
}));

var $scope, mainController, appFactoryMock, someServMock;

beforeEach(inject(function($rootScope, $controller, $http, $q, appFactory, someServ){
    appFactoryMock = appFactory;
    someServMock = someServ;
    $scope = $rootScope.$new();
    mainController = $controller("mainController", {
        $scope : $scope,
        $http : $http,
        appFactory : appFactoryMock
    });

}));

it('that mainController is calling appFactory methods', function(){
    spyOn(appFactoryMock, "getData");
    mainController.printData();
    scope.$root.$digest();
    expect(appFactoryMock.getData).toHaveBeenCalled();
})

it('that appFactory method foo calls someServ sendMsg', function(){
    spyOn(appFactoryMock, "foo");
    appFactoryMock.foo();
    expect(someServMock.sendMsg).toHaveBeenCalled();
});

Both the above tests are failing. For first one, error is: Cannot read property of undefined and for second one: expected spy sendMsg to have been called. First error occurs at: app.js file as shown in call stack. I have also debugged my tests using Debug option in karma chrome window. The printData() function is calling actual code in app.js but I have already mocked it.

Please anyone explain me why is it happening so and how to solve this issue? Why original code is being called and how can I make both these tests to pass.

I am doing unit testing using Karma and Jasmine. I have app.js as main source file:

app.service("someServ", function(){
  this.sendMsg = function(name){
    return "Hello " + name;
  }
})

app.factory("appFactory", function ($q, someServ) {
  function getData() {
    var defer = $q.defer();
    defer.resolve("Success message");
    return defer.promise;
} 

function foo(){
    var text = someServ.sendMsg("Message");
    alert(text);
}
return {
    getData : getData,
    foo : foo
}
})

app.controller("mainController",['$scope','$http','appFactory',function($scope, $http, appFactory){
var mct = this;
mct.printData = function(){
    var myPromise = appFactory.getData();
    myPromise
        .then(function(data){
            alert("Promise returned successfully. Data : " + data);
        }, function(error){
            alert("Something went wrong.... Error: "  + error);
        })
}
mct.showMsg = function(){
    appFactory.foo();
}
}]);

My testFile.js is as follows:

   beforeEach(module(function($provide){
    $provide.service("someServ", function(){
        this.sendMsg =   jasmine.createSpy('sendMsg').and.callFake(function(param){})
    });

    $provide.factory("appFactory", function(someServ, $q){
        function getData(){
            var defer = $q.defer();
            defer.resolve("Success message");
            return defer.promise;
        }
        function foo(){
            var facParam = "some text";
            someServ.sendMsg(facParam);
        }
        return {
            getData : getData,
            foo : foo
        }
    });
}));

var $scope, mainController, appFactoryMock, someServMock;

beforeEach(inject(function($rootScope, $controller, $http, $q, appFactory, someServ){
    appFactoryMock = appFactory;
    someServMock = someServ;
    $scope = $rootScope.$new();
    mainController = $controller("mainController", {
        $scope : $scope,
        $http : $http,
        appFactory : appFactoryMock
    });

}));

it('that mainController is calling appFactory methods', function(){
    spyOn(appFactoryMock, "getData");
    mainController.printData();
    scope.$root.$digest();
    expect(appFactoryMock.getData).toHaveBeenCalled();
})

it('that appFactory method foo calls someServ sendMsg', function(){
    spyOn(appFactoryMock, "foo");
    appFactoryMock.foo();
    expect(someServMock.sendMsg).toHaveBeenCalled();
});

Both the above tests are failing. For first one, error is: Cannot read property of undefined and for second one: expected spy sendMsg to have been called. First error occurs at: app.js file as shown in call stack. I have also debugged my tests using Debug option in karma chrome window. The printData() function is calling actual code in app.js but I have already mocked it.

Please anyone explain me why is it happening so and how to solve this issue? Why original code is being called and how can I make both these tests to pass.

Share Improve this question edited Jan 13, 2017 at 9:14 danwellman 9,3938 gold badges63 silver badges91 bronze badges asked Dec 6, 2015 at 18:52 AosisAosis 3116 silver badges18 bronze badges
Add a ment  | 

2 Answers 2

Reset to default 5

Jasmine's spy only checks if the function has been called, without firing the actual implementation. That's why getData().then throws an error.

As you can read on Jasmine's documentation you need to add .and.callThrough() to go through the original function.

I believe the first issue may be related to a syntax error you have in your code - in your first it block, what does the scope variable refer to?

本文标签: javascriptMocked service returning promise Cannot read property of undefinedStack Overflow