2012-12-18 23 views
5

किया गया था, मैं इकाई को "सेवा परत"/"अनुप्रयोग मुखौटा परत" विधि का परीक्षण करने की कोशिश कर रहा हूं।FakeItEasy का कहना है कि MustHaveHappened नहीं हुआ ... लेकिन यह

// Create a new order in the database for a customer. Given a customer id, 
// will create a new order and return an OrderDto for use in the presentation 
// layer. 
public OrderDto CreateOrderForCustomer(int customerId) 
{ 
    // Find the customer 
    var customer = _customerRepository.GetCustomerById(customerId); 

    // Create an order and apply special logic to get it ready for use. 
    var orderFactory = new OrderFactory(); 
    var order = orderFactory.CreateOrder(customer); 

    // IMPORTANT: This is what I'm trying to unit test ... 
    _orderRepository.Save(order); 

    order.Status = "Editing"; 

    // Using AutoMapper to turn this into a DTO that will be returned 
    // to the Presentation layer. The Mappings are created in the 
    // constructor and not depicted in this code snippet. 
    var orderDto = Mapper.Map<Order, OrderDto>(order); 

    return orderDto; 
} 

(।। नोट ... मैं स्पष्टता के लिए यहाँ प्रचुर नोट्स जोड़ दिया है मैं आमतौर पर इस बातूनी नहीं कर रहा हूँ)

इस विधि के बाद से: इस विधि इकाई परीक्षण करने के लिए मैं कोशिश कर रहा हूँ है नौकरी डोमेन लेयर विधियों और दृढ़ता परत विधियों को एक खाली ऑर्डर बनाने, इसे जारी रखने और इसे एक साधारण डीटीओ के रूप में वापस करने के लिए है, मुझे लगा कि यह FakeItEasy के लिए एक अच्छा काम था ... मैं बस यह सुनिश्चित करूँगा कि उन महत्वपूर्ण विधियां हैं यह सुनिश्चित करने के लिए ठीक से ऑर्केस्ट्रेट किया जा रहा है कि उन्हें FakeItEasy's MustHaveHappened() का उपयोग करके बुलाया जाता है।

तो, इस बात को ध्यान में साथ है, यहाँ मैं बनाया इकाई परीक्षण है:

[TestMethod] 
public void CreateOrderForCustomer_ValidCustomer_CreatesNewOrder() 
{ 
    // Arrange 
    var customer = _customerRepository.GetCustomerById(1); 
    Assert.AreEqual(0, customer.Orders.Count); 

    // Act 
    var orderDto = _orderEntryService.CreateOrderForCustomer(1); 

    // Assert 

    // Here I'm trying to make sure to re-create the order that was actually 
    // sent into the _customerRepository.Save() ... I should be able to 
    // simple un-map the OrderDto back to an Order, and undo the property 
    // change. 
    var order = Mapper.Map<OrderDto, Order>(orderDto); 
    order.Status = "New"; 

    A.CallTo(() => _customerRepository.GetCustomerById(1)).MustHaveHappened(); 

    // **THIS CAUSES AN EXCEPTION** 
    A.CallTo(() => _orderRepository.Save(order)).MustHaveHappened(); 
    Assert.AreEqual(1, customer.Orders.Count); 
} 

इकाई परीक्षण में, मैं वास्तविक क्रम कि परीक्षण के अंतर्गत विधि में बनाया गया था उपयोग नहीं कर सकते, मैं करने की कोशिश अगली सबसे अच्छी बात करें ... आदेश के डीटीओ संस्करण को परीक्षण के तहत विधि द्वारा वापस लौटाया गया है, ऑर्डर के डीटीओ संस्करण को डोमेन मॉडल ऑर्डर के नए उदाहरण पर वापस लाएं और सुनिश्चित करें कि गुण समान हैं इसे FakeItEasy के MustHaveHappened() पर भेजने से पहले।

मैंने इकाई परीक्षण को डीबग किया है और सक्रिय ऑर्डर के गुणों को बनाम ऑर्डर गुणों के विरुद्ध देखा है ... मैं आपको आश्वासन देता हूं, वे समान हैं। इसके अलावा, मैं डीबगिंग के माध्यम से पुष्टि कर सकता हूं कि _customerRepository.Save (ऑर्डर) वास्तव में कहा जा रहा है।

प्रश्न .MustHaveHappened है() में नाकाम रहने क्योंकि मैं अनिवार्य रूप से आदेश वस्तु के दो अलग-अलग मामलों में भेज रहा है - भले ही उनके गुणों समान हैं? भले ही गुण समान हैं, फिर भी FakeItEasy को इनपुट पैरामीटर का एक ही उदाहरण चाहिए ताकि यह सुनिश्चित किया जा सके कि विधि कॉल हुआ है?

इसके अलावा, मैं कैसे बात की इस तरह का परीक्षण किया जाना चाहिए के लिए कोई सुझाव है (यानी एक आर्केस्ट्रा/सेवा/"आवेदन मुखौटा"/क्या-कभी आप-करना-चाहते-कॉल-यह परत विधि)?

उत्तर

16

है .MustHaveHappened() विफल रहा क्योंकि मैं अनिवार्य रूप से ऑर्डर ऑब्जेक्ट के दो अलग-अलग उदाहरणों में भेज रहा हूं - भले ही उनकी गुण समान हों?

हां। FakeItEasy .Equals का उपयोग करेगा, जो (जब तक आपकी कक्षा इसे ओवरराइड नहीं करती) संदर्भ प्रकार समानता संदर्भ के लिए डिफ़ॉल्ट करता है।

(...) FakeItEasy इनपुट पैरामीटर का एक ही उदाहरण की जरूरत है सुनिश्चित करें कि विधि कॉल हुआ है करता है?

नहीं, आप इस तरह कस्टम तर्क मिलान कर सकते हैं:

A.CallTo(() => _orderRepository.Save(A<Order>.That.Matches(o => 
    o.Status == "New" && 
    o.Id == 10 
))).MustHaveHappened(); 

लेकिन, इस समस्या को अपने कोड के साथ एक मुद्दे का पता चला। आपके नमूने से यह स्पष्ट है कि आप निर्भरता के रूप में _customerRepository इंजेक्शन कर रहे हैं। एक दम बढ़िया। आप OrderFactory के साथ ऐसा क्यों नहीं करते? अगर इसे इंटरफ़ेस/बेस क्लास निर्भरता के माध्यम से इंजेक्शन दिया गया था, तो आप आसानी से नकली (नकली) कर सकते हैं और आपकी वर्तमान समस्या मौजूद नहीं होगी।

यदि आप अपना कोड बदल सकते हैं तो मैं कारखाने को इंजेक्शन देने का सुझाव दूंगा (सरल दिशानिर्देश - "new एस अच्छी खबर है!")। यदि नहीं, तो ऊपर दिए गए नमूने में आदेश गुणों को सत्यापित करने के लिए कस्टम मैचर्स का उपयोग करें।

+0

धन्यवाद, धन्यवाद, धन्यवाद! ऑर्डर फैक्ट्री के बारे में विशेष रूप से महान युक्तियाँ! –

+0

यह नहीं है कि संदर्भ तुलना का उपयोग किया जाता है, यह है कि बराबर-कार्यान्वयन का उपयोग किया जाता है। इसलिए यदि आप समकक्ष-विधि को बराबर आदेशों पर विचार करने के लिए ओवरराइड करते हैं जो समस्या को हल भी करेगा। –

+0

@ PatrikHägne: हाँ, मेरे मानसिक शॉर्टकट जंगली चल रहे हैं, अनुस्मारक के लिए धन्यवाद। –

संबंधित मुद्दे