2012-12-18 11 views
5

Próbuję przetestować metodę "warstwy serwisowej"/"warstwy elewacji aplikacji". Jest to metoda Próbuję badanej jednostki:FakeItEasy mówi, że MustHaveHappened się nie stało ... ale wykonałem

// 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; 
} 

(.. Uwaga ... Dodałem obszerne notatki tu dla jasności nie jestem zwykle to rozmowny)

Ponieważ metoda ta na zadaniem jest uporządkowanie metod Warstwy Dominiki i Metod Persistence Layer w celu utworzenia pustego zamówienia, utrzymania go i zwrócenia go jako zwykłego DTO, uznałem, że to świetna robota dla FakeItEasy ... Po prostu upewnię się, że te krytyczne metody są być odpowiednio zorganizowanymi, upewniając się, że zostali wezwani za pomocą FakeItEasy's MustHaveHappened().

więc mając to na uwadze, oto test jednostka stworzyłem:

[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); 
} 

W badanej jednostki, nie może uzyskać dostępu do rzeczywistej Order, który został utworzony w sposobie badanego, staram się wykonaj następną najlepszą rzeczą ... weź wersję DTO zamówienia, które zostanie ZWRÓCONE przez testowaną metodę, zamapuj wersję zamówienia DTO zamówienia na nowe wystąpienie modelu domeny Zamów i upewnij się, że właściwości są takie same przed wysłaniem go do MustHaveHappened() FakeItEasy's.

Przeprowadziłem debugowanie testu jednostki i przyjrzałem się właściwościom WARTOŚCI RZECZYWISTEJ w stosunku do właściwości Zakonu FAKED ... Zapewniam cię, że są identyczne. Ponadto, poprzez debugowanie, mogę potwierdzić, że _customerRepository.Save (kolejność) jest rzeczywiście wywoływana.

PYTANIE Czy .MustHaveHappened() niepowodzeniem, ponieważ mam w zasadzie wysyłania w dwóch różnych wystąpień przedmiotu zamówienia - mimo że ich właściwości są identyczne? Mimo że właściwości są takie same, czy FakeItEasy potrzebuje tego samego wystąpienia parametru wejściowego, aby upewnić się, że nastąpiło wywołanie metody?

Co więcej, wszelkie sugestie dotyczące tego, jak powinienem testować tego typu rzeczy (np. Metoda aranżacji/usługi/"elewacji aplikacji"/co jeszcze chcesz wywołać)?

Odpowiedz

16

Czy .MustHaveHappened() nie działa, ponieważ zasadniczo wysyłam dwa różne wystąpienia obiektu Order - mimo że ich właściwości są identyczne?

Tak. FakeItEasy użyje .Equals, który (o ile twoja klasa go nie zastąpi) dla typów odniesienia przyjmuje wartość domyślną dla odniesienia do równości.

(...) czy FakeItEasy potrzebuje tego samego wystąpienia parametru wejściowego, aby upewnić się, że nastąpiło wywołanie metody?

Nie można zrobić niestandardowe dopasowanie argumentów tak:

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

Ale problem ten ujawnił problem z kodem. Z twojej próbki wynika, że ​​wstrzykujesz _customerRepository jako zależność. To wspaniale. Dlaczego nie zrobisz tego samego z OrderFactory? Jeśli został on wstrzyknięty za pomocą zależności interfejs/klasa bazowa, możesz wtedy łatwo udawać (fałszywe), a twój obecny problem nie istnieje.

Jeśli możesz zmienić kod, sugeruję wstrzyknięcie do fabryki (zgodnie z prostą wytyczną - "no new s to dobra wiadomość!"). Jeśli nie, użyj niestandardowych dopasowań, by zweryfikować właściwości zamówienia, tak jak zrobiłem to w powyższym przykładzie.

+0

Dziękuję, dziękuję, dziękuję! Świetne wskazówki dookoła, szczególnie w odniesieniu do OrderFactory! –

+0

Nie chodzi o to, że używane jest porównanie referencyjne, to znaczy, że używana jest implementacja równań. Więc jeśli zastąpisz metodę równości, by uważać równoważne zamówienia za równe, to również rozwiązałoby problem. –

+0

@ PatrikHägne: Tak, moje mentalne skróty dziczeją, dzięki za przypomnienie. –

Powiązane problemy