Jasmine(Karma)测试失败了$ rootScope。$ watch

时间:2016-11-18 16:26:55

标签: angularjs unit-testing jasmine karma-runner

我正在尝试在我的控制器中测试一个函数,该函数在采取任何操作之前首先监视要加载的字典。

我得到的问题是我的测试失败,因为手表似乎没有运行。

我的控制器功能

function setPageTitle(title) {
        $rootScope.$watch('dictionary', function(dictionary) {
            if (dictionary) {
                if ($location.$$path != '/dashboard') {
                    $rootScope.pageTitle = $rootScope.dictionary.pageTitles[title] || $rootScope.dictionary.pageTitles.dashboard || 'Dashboard';
                } else {
                    $rootScope.pageTitle = $rootScope.dictionary.pageTitles.dashboard || 'Dashboard';
                }                    
            }
        });
    }

我的测试...

describe('AppController function', function() {

var rootScope, scope, $location, $window, controller, createController, cacheFactory, toastr;

beforeEach(module('mockedDashboard'));

beforeEach(inject(function(_$rootScope_, $controller, _$location_, _$window_, _toastr_, _$timeout_) {
    $location = _$location_;
    $window = _$window_;
    $timeout = _$timeout_;
    scope = _$rootScope_.$new();
    rootScope = _$rootScope_;
    toastr = _toastr_;

    createController = function() {
        return $controller('AppController', {
            '$scope': scope
        });
    };
    controller = createController();
}));

// We are using CacheFactory in this project, when running multiple tests on the controller
// we need to destroy the cache for each test as the controller is initialized for each test.
afterEach(inject(function(_CacheFactory_) {
    cacheFactory = _CacheFactory_;
    cacheFactory.destroy('defaultCache');
}));

describe('setPageTitle()', function() {

    it('should update the $rootScope.pageTitle', function() {


        scope.setPageTitle('logIn');

        scope.$apply();

        expect(rootScope.pageTitle).toBe('LOG IN');

    });
});
});

失败消息

  

预计未定义为'登录'

永远不会设置

rootScope.pageTitle,因为当测试调用函数时手表不会运行。我怎么能绕过这个?

我试过scope.$apply()我读过的应该会触发$ watch,但它仍然不起作用。

修改 我尝试使用done函数,但是测试仍然失败,因为rootScope.pageTitle仍然显示为未定义。 3000ms应该有足够的时间来工作,通常这样做的时间少于500毫秒。 (我也知道代码有效,因为这个测试写的太晚了)

    describe('setPageTitle()', function() {

    it('should update the $rootScope.pageTitle', function(done) {

        scope.setPageTitle('logIn');

        scope.$apply();

        setTimeout(function() {
            // console.log('dictionary: ' + rootScope.dictionary.pageTitles.logIn);
            console.log('rootScope.pageTitle: ' + rootScope.pageTitle);
            expect(rootScope.pageTitle).toBe('LOG IN');
            // expect(true).toBe(false);
            done();
        }, 3000);
    });
});

3 个答案:

答案 0 :(得分:0)

看起来你的测试是同步测试,因此Karma认为一旦函数返回就完成了。不幸的是,实际情况并非如此,因为您需要等待$apply的影响发生,这需要另一次通过事件循环。您需要通过添加done参数将测试转换为异步测试,并在触发监视后以某种方式调用它。

it('description', function(done) {
    // do your setup things here
    scope.$apply();

    setTimeout(function() {
        // make your assertions here
        done()
    }, 25);
})

当然,使用setTimeout是一种非常难看的方式来等待必要的时间,如果还有其他一些你可以注意的事件,它会更优雅。

答案 1 :(得分:0)

嗯,很明显 - 你的测试失败了,因为代码$rootScope.$watch('dictionary', function(dictionary) { if (dictionary) { ... } }); 没有运行。

$rootScope.dictionary

由于没有明确设置用于测试目的,undefined describe('setPageTitle()', function() { it('should update the $rootScope.pageTitle', function() { scope.setPageTitle('logIn'); rootScope.dictionary = { 'whatever you': 'need here' }; scope.$apply(); expect(rootScope.pageTitle).toBe('LOG IN'); }); }); 可能存在问题。

试试这个

$digest

顺便说一句 - 完全没有必要使用异步测试用例,因为scope.$apply();将在>>> s = 'a;;b;;;c;;;;d' >>> pattern = ';{2,}' >>> def f(m): return m.group(0)[1:] >>> re.sub(pattern, f, s) 'a;b;;c;;;d' >>> 行同步调用。

答案 2 :(得分:0)

对您的测试用例进行的少量更改很少,您可以尝试一下,

 describe('setPageTitle()', function() {

 it('should update the $rootScope.pageTitle', function() {
      rootScope.dictionary = "someValue"; // As you were watching this object assign some value and then apply $digest

      // Instead of $apply use $digest with rootscope
      rootscope.$digest();
      expect(rootScope.pageTitle).toBe('LOG IN');
});
});