2014-12-25 2 views
1

Я хочу использовать контексты с жасмином, чтобы я мог организовать то, что возвратит мой мак. Вот какой-то псевдо-код, демонстрирующий, что я хочу делать. Я ожидаю, что оба эти ожидания пройдут:Использование контекстов с жасмином

describe('a module', function(){ 
    var whatTheFunctionReturns; 
    beforeEach(function(){ 
     module('anApp', function($provide){ 
      $provide.value('aFactory', { aFunction: whatTheFunctionReturns }) 
     } 
    }); 

    describe('when the function returns alpha', function(){ 
     whatTheFunctionReturns = 'alpha' 

     it('should get data from a service', function(){ 
      expect(aFactory.aFunction).toEqual('alpha') 
     }); 
    }); 
    describe('when the function returns beta', function(){ 
     whatTheFunctionReturns = 'beta' 

     it('should get data from a service', function(){ 
      expect(aFactory.aFunction).toEqual('beta') 
     }); 
    }); 
}); 

Прочтите внимательно. Вы видите, что я пытаюсь сделать? Код

$provide.value('aFactory', { aFunction: whatTheFunctionReturns }) 

пишется один раз в beforeEach блоке, но переменная

whatTheFunctionReturns 

изменяется в двух блоков, описывают when the function returns alpha и when the function returns beta.

Однако, это не работает. Вот некоторые реальный код, где я пытаюсь проверить контроллер и макет из завода, что это зависит от:

describe('firstController', function(){ 
    var $rootScope, $scope, $controller 
    var message = 'I am message default' 

    beforeEach(function(){ 
     module('App',function($provide){ 
      $provide.value('ServiceData', { message: message}) 
     }); 
     inject(function(_$rootScope_,_$controller_){ 
      $rootScope = _$rootScope_ 
      $scope = $rootScope.$new() 
      $controller = _$controller_ 
      $controller('firstController', { '$rootScope' : $rootScope, '$scope' : $scope }) 
     }); 
    }); 

    describe('when message 1', function(){ 
     beforeEach(function(){ 
      message = 'I am message one' 
     }); 
     it('should get data from a service', function(){ 
      expect($scope.serviceData.message).toEqual('1') // using wrong data so I can see what data is being returned in the error message 
     }); 
    }); 

    describe('when message 2', function(){ 
     beforeEach(function(){ 
      message = 'I am message two' 
     }); 
     it('should get data from a service', function(){ 
      expect($scope.serviceData.message).toEqual('2') // using wrong data so I can see what data is being returned in the error message 
     }); 
    }); 
}); 

Вот сообщение об ошибке я получаю обратно:

Firefox 34.0.0 (Ubuntu) firstController when message 1 should get data from a service FAILED 
    Expected 'I am message default' to equal '1'. 

Firefox 34.0.0 (Ubuntu) firstController when message 2 should get data from a service FAILED 
    Expected 'I am message one' to equal '2'. 

Это половина работает. Переменная обновляется, но только в последнем блоке описания ('when message 2'). Вот что я ожидал быть возвращен:

Firefox 34.0.0 (Ubuntu) firstController when message 1 should get data from a service FAILED 
    Expected 'I am message one' to equal '1'. 

Firefox 34.0.0 (Ubuntu) firstController when message 2 should get data from a service FAILED 
    Expected 'I am message two' to equal '2'. 

Как я могу добиться этого? Вы видите, что я пытаюсь сделать с блоками описания?

+0

Почему бы вам не сделать 'beforeEach (функция (ServiceData) { ServiceData.message = 'Я сообщение два' });' – Chandermani

+0

@Chandermani Вы должны были бы 'впрыснуть()' а – james

+0

вы должны принять посмотрите на sinon для насмешки/stubbing – james

ответ

6

Вы неправильно поняли, как Жасмин строит тестовый пример перед выполнением каждого теста.

Взгляните на это и выполнить его:

describe("Test", function(){ 
    console.info("Calling beforeEach() before describe()"); 
    beforeEach(function(){ 
     console.info("Running before()"); 
    }); 

    console.info("Calling describe() A"); 
    describe("describe A", function(){ 
     console.info("Calling it() A 0"); 

     it('should A 0', function(){ 
      console.info("Running it() A 1"); 
      expect("test to be").toBe("implemented"); 
     }); 

     console.info("Calling it() A 1"); 
     it('should A 1', function(){ 
      console.info("Running it() A 2"); 
      expect("test to be").toBe("implemented"); 
     }); 

     console.info("Calling it() A 2"); 
     it('should A 2', function(){ 
      console.info("Running it() A 3"); 
      expect("test to be").toBe("implemented"); 
     }); 
    }); 

}); 

В консоли вы будете наблюдать это:

Calling beforeEach() before describe() 
Calling describe() A 
Calling it() A 0 
Calling it() A 1 
Calling it() A 2 
Running before() 
Running it() A 1 
Running before() 
Running it() A 2 
Running before() 
Running it() A 3 

Что здесь происходит?

Когда вы вызываете describe(), код в функциях обратного вызова, который вы предоставляете, будет выполнен. Последующие вызовы другим describe() s будут выполнять свои обратные вызовы. Каждый вызов к it(), beforeEach() и afterEach() в очередь переданной функции обратного вызова во внутреннем дереве очереди, то перед тем будет предварять каждую отрасль, после будет добавляться к этой ветви. Затем очередь переводится один за другим, а Жасмин выполняет сохраненный обратный вызов для каждого шага.

При поиске вашего первого кода это означает, что все ваши поручения whatTheFunctionReturns выполняются, то каждый it() (предваряется beforeEach()) в настоящее время выполняется


Что вы должны сделать:

describe('a module', function(){ 
    var whatTheFunctionReturns; 

    // pepare to run in beforeEach() 
    function _beforeModule(){ 
     module('anApp', function($provide){ 
      $provide.value('aFactory', { aFunction: whatTheFunctionReturns }) 
     } 
    } 

    describe('when the function returns alpha', function(){ 
     beforeEach(function(){ 
      whatTheFunctionReturns = 'alpha'; 
      _beforeModule(); 
     }); 

     it('should get data from a service', function(){ 
      expect(aFactory.aFunction).toEqual('alpha') 
     }); 
    }); 
    describe('when the function returns beta', function(){ 
     beforeEach(function(){ 
      whatTheFunctionReturns = 'beta'; 
      _beforeModule(); 
     }); 

     it('should get data from a service', function(){ 
      expect(aFactory.aFunction).toEqual('beta') 
     }); 
    }); 
}); 

Вы должны обернуть присвоения в beforeEach() или it() блоках.

+0

@ Андрю Айзенберг, я не уверен, какое влияние [ваше редактирование] (http://stackoverflow.com/posts/27668957/revisions) имеет значение моего предложения. Я бы предпочел вернуть его в предыдущую ревизию без обернутого 'inject()' вызывает вокруг обратных вызовов 'it()', так как исходный код, отправленный TO, тоже не содержит их. И, на мой взгляд, ошибка прежде всего заключается в непонимании того, как Жасмин выполнит тест. –

+0

Спасибо за подробный ответ. Хотя код в вашем последнем блоке работает (все ожидания проходят), он перестает работать, когда я пытаюсь ввести мой контроллер: 'inject (function ($ rootScope, $ controller) { scope = $ rootScope. $ New() $ controller ('firstController', {$ scope: $ scope} \t); }); 'Когда я использую' injection', происходит такое же поведение, которое я описал ранее. whatTheFunctionReturns установлен в неопределенный, а затем альфа, а не бета ... – Starkers

+1

Андреевская модификация вернулась. Конечно, моя адаптация не была полной: код, который выполняется в первом 'beforeEach()', должен быть вызван после назначения в других вызовах 'beforeEach()'. Последний код исправлен. Примечание: первый/верхний блок 'beforeEach()' больше не выходит, код, который был выполнен в этом 'beforeEach()' теперь вызывается в '' _beforeModule() '" –

0

К сожалению, Jasmine не имеет понятия Contexts в своем DSL, что означает, что технически невозможно повторно использовать тело ожиданий с динамическим объемом и проверить его поведение на разные значения. Все, что вы делаете, чтобы получить этот уровень повторного использования с Jasmine, будет обходным путем, не разработанным создателями.

В вашем демо-коде, когда вы вызываете функцию $ controller внутри первого beforeEach, он будет разрешать все свои зависимости, используя значение по умолчанию, независимо от того, что вы делаете.

$controller('firstController', { '$rootScope' : $rootScope, '$scope' : $scope }) 
0

Я считаю, что проблема, которую вы столкнетесь в том, что переменная, используемая для assigne вашей «сообщение» в службе просто значение объекта. Это проблема с javascript больше, чем проблема с жасмином.

Не имеет значения, что вы его изменяете после вы назначаете его объекту, который вы предоставляете службе. Например:

var a = 1; 
var b = a; 
a = 2; 
console.log(b); // will print out '1' 

Что вы хотите, чтобы иметь возможность изменить объект, который вы предоставили к службе после первого beforeEach, так же, как так:

describe('firstController', function() { 
    var $rootScope, $scope, $controller, serviceData 

    beforeEach(function(){ 
     serviceData = { message: 'I am message default' } 
     module('App',function($provide){ 
      $provide.value('ServiceData', serviceData) // keep a reference to the object 
     }); 
     inject(function(_$rootScope_,_$controller_){ 
      $rootScope = _$rootScope_ 
      $scope = $rootScope.$new() 
      $controller = _$controller_ 
      $controller('firstController', { '$rootScope' : $rootScope, '$scope' : $scope }) 
     }); 
    }); 

    describe('when message 1', function(){ 
     beforeEach(function(){ 
      serviceData.message = 'I am message one' // that way, you modify the object that your 'ServiceData' provider holds. 
     }); 
     it('should get data from a service', function(){ 
      expect($scope.serviceData.message).toEqual('1') 
     }); 
    }); 

    describe('when message 2', function(){ 
     beforeEach(function(){ 
      serviceData.message = 'I am message two' 
     }); 
     it('should get data from a service', function(){ 
      expect($scope.serviceData.message).toEqual('2') 
     }); 
    }); 
}); 

Отказ от ответственности: Я не 100% уверены в внутренней работе $ обеспечивают.значение. Если вышеуказанное не работает, возможно, это связано с тем, что объект, присвоенный функции $ offer.value, клонируется внутри.

Смежные вопросы