2014-12-25 40 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 alphawhen 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

您誤解了Jasmine在執行每個測試之前如何構建測試用例。

看看這一點,並執行它:

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()的呼叫將執行其回調。每次調用it()beforeEach()afterEach()將排隊傳入回調在內部隊列樹,前將被預置到每個分支中,之後將被附加到該分支。然後隊列被逐個移動,Jasmine將爲每個步驟執行存儲的回調。

當尋找到你的第一個代碼,這意味着的whatTheFunctionReturns的所有作業都已執行,然後每個it()(由beforeEach() preceeded)正在執行


你應該做的:

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

@Andrew Eisenberg,我不確定[編輯](http://stackoverflow.com/posts/27668957/revisions)對我建議的意義有什麼影響。由於TO發佈的原始代碼不包含它們,因此我希望將它還原爲之前的修訂版本,而不用在'it()'回調周圍包裝'inject()'調用。在我看來,錯誤主要在於茉莉花將如何執行測試的誤解。 –

+0

感謝您的詳細解答。儘管您最後一個塊中的代碼確實有效(所有預期都會通過),但當我嘗試注入控制器時,它停止工作: 'inject(function($ rootScope,$ controller)scope = $ rootScope。$ new() $ controller('firstController', \t {$ scope:$ scope} \t); });'當我使用'inject'時,會出現之前描述的相同行爲。 whatTheFunctionReturns設置爲undefined,然後是alpha,而不是beta ... – Starkers

+1

Andrew的修改已恢復。當然,我的適應並不完整:在beforeEach()調用之後,在第一個'beforeEach()'中執行的代碼必須被調用。最後的代碼修復。注意:第一個/最頂層的'beforeEach()'塊不再退出,在'beforeEach()'中執行的代碼現在在_beforeModule()中調用。「 –

0

不幸的是,Jasmine在其DSL中沒有Contexts的概念,這意味着在技術上不可能重複使用動態範圍的期望主體並根據不同的值測試其行爲。爲了使Jasmine具有這種可重用性,您所做的每件事都將是一種解決方法,不是由創作者設計的。

在您的演示代碼中,當您在第一個beforeEach中調用$ controller函數時,無論您做什麼,它都將使用默認值解析其所有依賴項。

$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') 
     }); 
    }); 
}); 

免責聲明:我關於$ provide.value的內部工作原理並非100%確定。如果上述不起作用,可能是因爲賦予$ provide.value函數的對象在內部被克隆。