我正在尝试测试Angular.js控制器。我实际上正在测试一个模拟后端的调用,它返回一些虚拟数据。当我获取数据时,我调用服务方法,将结果作为参数传递。 现在,该服务被注入到我试图测试的控制器中,并且有一个$ scope。$ watch方法,它查找服务中更新的值,并设置控制器范围内的数据。
$scope.$watch(function(){
return FileService.getFileData();
}, function (newValue) {
self.fileData = newValue;
self.displayData = [].concat(self.fileData);
});
测试:
describe('Filebrowser', function() {
var scope;
var controller;
beforeEach(module('oide.filebrowser'));
describe('FilebrowserController Test', function() {
var httpBackend;
var http;
beforeEach(inject(function($controller, $rootScope, $httpBackend, $http){
// The injector unwraps the underscores (_) from around the parameter names when matching
httpBackend = $httpBackend;
scope = $rootScope.$new();
controller = $controller;
http = $http
// Mock FileService
var currentDirectory = ['/', 'home', 'saurabh'];
var currentFile = '/home/saurabh/testfile';
var rootDirectory = '/home/saurabh';
var volume_info = {
'percent': '10',
'used': '10',
'size': '100'
};
var fileData;
var groups = ['saurabh', 'sudo', 'adm'];
mockFileService = {
getCurrentDirectory: function() {
return currentDirectory;
},
getFileData: function() {
return currentFile;
},
getRootDirectory: function() {
return rootDirectory;
},
getVolumeInfo: function() {
return volume_info;
},
setFileData: function(data) {
fileData = data;
},
getFileData: function(){
return fileData;
}
};
// Mock FilesystemService
mockFilesystemService = {
getGroups: function() {
return groups;
}
};
// Mock FiletreeService
mockFiletreeService = {};
controller = $controller(
'FilebrowserController as ctrl', {
$scope: scope,
FileService: mockFileService,
FilesystemService: mockFilesystemService,
FBFiletreeService: mockFiletreeService,
$modal: {}
});
scope.ctrl = controller;
scope.$apply();
}));
it('should fetch files for a particular directory', function(){
http.get('/filebrowser/filetree/a/dir')
.success(function(data){
mockFileService.setFileData(data);
setTimeout(function() {
console.log(scope.ctrl.fileData);
expect(scope.ctrl.fileData).toBeDefined();
}, 1);
})
.error(function(data){
console.log(data);
});
httpBackend.whenGET('/filebrowser/filetree/a/dir').respond(function(){
var files = [{
"filepath": "/home/saurabh/file1",
"filename": "file1",
"group": "saurabh",
"is_accessible": true,
"perm": "-rw-rw-r--",
"perm_string": "664",
"size": "0.0 KiB",
"type": "file"
}, {
"filepath": "/home/saurabh/file2",
"filename": "file2",
"group": "root",
"is_accessible": false,
"perm": "-rw-r--r--",
"perm_string": "644",
"size": "0.0 KiB",
"type": "file"
},
{
"filepath": "/home/saurabh/file3",
"filename": "file3",
"group": "saurabh",
"is_accessible": true,
"perm": "-rw-rw-r--",
"perm_string": "664",
"size": "0.0 KiB",
"type": "file"
}];
return [200, files];
});
httpBackend.flush();
// });
});
});
});
在我的测试中,我试图检查是否已定义fileData变量。有一个控制台日志语句,它将fileData变量输出到控制台。但是,expect语句失败并出现以下错误:
PhantomJS 1.9.8 (Linux) ERROR
TypeError: 'null' is not an object (evaluating 'this.results_.addResult')
at /home/saurabh/workspace/OIDE/oide/client/node_modules/karma-jasmine/lib/jasmine.js:2348
两个问题:
答案 0 :(得分:0)
这是否是'正确'的方式可能仅仅是一个意见问题,但这是我的:
1.)我看不到你所有的控制器代码,但通常你不需要像你在这里一样在你的测试中编写实际的http.get调用,这是你的控制器的工作。您的测试应该实例化控制器(或执行控制器正在侦听的任何操作)以触发该http调用,然后您只是断言期望(就像它正确设置您的$ scope变量一样)。
2.。)为什么此服务调用FileService.getFileData()
包含在$scope.watch()
中?如果您的答案是您只想在上一次成功的http呼叫之后触发此呼叫,那么您应该在第一次呼叫后将第二个呼叫包裹在承诺(.then
或.success
)中。
例如:
function makeServiceCalls() {
mockFileService.getCurrentDirectory()
.success( function() {
FileService.getFileData()
.then(// do more stuff);
})
.error( function() {
// wah-wahhhh
}
}
通过单元测试可能很棘手。在您认为否定案例有效之前,您应该确保先测试否定案例。