【问题标题】:Adding test cases for a basic controller for ng-click event using Jasmine使用 Jasmine 为 ng-click 事件的基本控制器添加测试用例
【发布时间】:2017-01-02 15:01:49
【问题描述】:

我正在尝试使用 karma-jasmine,并且我正在研究一些基本示例。

I have created one small plnkr 只做两件事:

  1. 添加数字
  2. 在单击按钮时显示一些硬编码值

这是我的MainController.spec.js

describe('Main Controller', function () {
    var $controller, MainController, UserFactory;
    var data = {
        "name": "Shashank",
        "rank": "1"
    }

    beforeEach(angular.mock.module('app'));

    beforeEach(inject(function (_$controller_, _UserFactory_) {
        $controller = _$controller_;
        UserFactory = _UserFactory_;
        MainController = $controller('MainController', {UserFactory: UserFactory});

        spyOn(MainController, 'add').and.callThrough();
        spyOn(MainController, 'getHardData').and.callThrough();
    }))

    it('should be defined', function () {
        expect(MainController).toBeDefined();
    })

    it('should have number = 3', function () {
        expect(MainController.number).toEqual(5)
    })

    it('add() should assign value properly', function () {
//        expect(MainController.add).toHaveBeenCalled();
    })

    it('getHardData should assign the exact data', function () {
//        expect(MainController.getHardData).toHaveBeenCalled();
//        expect(MainController.data).toEqual(data);
    })

})

对于附件 plnkr 中提到的控制器,我认为我应该只测试 2 件事:

  1. 测试添加是否正常工作。
  2. 测试按钮后面的数据是否正确

问题:

  1. 取消注释上述任何行会导致错误

Chrome 55.0.2883 (Windows 7 0.0.0) 主控制器 add() 应该正确分配值失败

预期的间谍添加已被调用。 在对象。 (控制器/MainController.spec.js:28:36) Chrome 55.0.2883(Windows 7 0.0.0):执行 4 次,共 4 次(1 次失败)(0.016 秒 / 0.012 秒)

  1. 另外,在 $controller('MainController', {UserFactory: UserFactory}); 中,我知道我们正在分配 factory 的值,但将其更改为 $controller('MainController', {}); 不会引发任何错误。 为什么?

请帮助我理解我的愚蠢错误。

任何了解业力和茉莉花的最佳实践/示例的好链接都会有很大帮助

【问题讨论】:

    标签: angularjs jasmine karma-jasmine


    【解决方案1】:

    查看控制器,它公开了四个属性 - 两个是函数(如果算上在 add 函数中创建的 sumVal,则有五个属性)。

    属性datanumber 可以简单地断言它们在控制器创建后被正确初始化,就像您对其中之一所做的那样。

    当谈到add 函数时,最明显的测试是它应该添加两个参数并正确分配结果。由于该函数采用两个参数,因此您可以添加许多其他测试。不带参数调用函数,用一个数字和一个字符串调用函数等。如果你想测试这通常取决于用例和你的测试策略。

    getHardData 函数不接受任何参数,因此您要测试的是它使用了UserFactory 并且它正确地分配了结果。


    如果您取消注释代码,测试失败的原因仅仅是因为从未调用过函数。您的控制器中没有任何内容在控制器初始化时调用 addgetHardData 方法,并且您的测试中没有任何内容调用它们。

    为了使测试正常工作,您必须这样做:

    it('add() should assign value properly', function() {
      MainController.add();
      expect(MainController.add).toHaveBeenCalled();
    });
    

    然而,这是一个无用的测试,因为您没有测试任何自己的功能。

    相反,您应该例如这样做:

    it('add() should assign value properly', function() {
    
      expect(MainController.sumVal).toBeUndefined();
    
      MainController.add(5, 10);
    
      expect(MainController.sumVal).toBe(15);
    });
    

    您不需要监视您正在测试的控制器方法,因为您将手动调用它们。

    当你有一个调用另一个依赖的控制器方法时,你想使用间谍,比如getHardData

    您不希望在测试中使用UserFactory 的真正实现,因此您可以使用间谍来中断调用并控制它返回的内容。

    例如:

    it('getHardData should assign the exact data', function() {
    
      // Set up the spy and the return value
      spyOn(UserFactory, 'getData').and.returnValue(data);
    
      // Call the method that you are testing
      MainController.getHardData();
    
      // Assert that the dependency was called
      expect(UserFactory.getData).toHaveBeenCalled();
    
      // Assert that the returned data was assigned correctly
      expect(MainController.data).toEqual(data);
    });
    

    另一种方法是创建一个模拟实现并在您的控制器中使用它:

    var MainController,
      data = {
        name: "Shashank",
        rank: "1"
      },
      UserFactory = {
        getData: function() {
          return data;
        }
      };
    
    beforeEach(function() {
    
      angular.mock.module('app');
    
      inject(function($controller) {
    
        MainController = $controller('MainController', {
          UserFactory: UserFactory
        });
      });
    });
    
    it('getHardData should assign the exact data', function() {
    
      // Set up the spy
      spyOn(UserFactory, 'getData').and.callThrough();
    
      // Call the method that you are testing
      MainController.getHardData();
    
      // Assert that the dependency was called
      expect(UserFactory.getData).toHaveBeenCalled();
    
      // Assert that the returned data was assigned correctly
      expect(MainController.data).toEqual(data);
    });
    

    请注意,间谍现在使用and.callThrough() 而不是and.returnValue(data)。如果你不使用这个调用将被间谍中断并且你的模拟实现将不会被使用。

    $controller('MainController', {}); 没有抛出任何错误的原因是,当传递一个空对象作为第二个参数(或根本没有参数 - $controller('MainController'))时,真正的依赖项将被自动注入,这与你现在有。

    【讨论】:

    • 非常感谢您的详尽回答。它回答了我心中的许多疑问。 :)
    • @ShashankVivek 而add 函数将结果分配给sumVal?
    • 请忽略。我的坏:3
    猜你喜欢
    • 1970-01-01
    • 2013-06-24
    • 1970-01-01
    • 2016-07-25
    • 2015-02-15
    • 2017-02-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多