使用$ httpBackend和$ scope对Angular.js进行单元测试。$ watch

时间:2016-01-12 22:17:27

标签: javascript angularjs unit-testing jasmine

我正在尝试测试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

两个问题:

  1. 我在这里做错了什么?
  2. 这是使用模拟HTTP后端进行测试的正确方法吗?

1 个答案:

答案 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
  }
} 

通过单元测试可能很棘手。在您认为否定案例有效之前,您应该确保先测试否定案例。