Czy test jednostkowy jest uważany za kruchy, jeśli zawiedzie, gdy zmienia się logika biznesowa?

27

Proszę zobaczyć kod poniżej; sprawdza, czy osoba z płcią żeńską kwalifikuje się do oferty1:

[Fact]
public void ReturnsFalseWhenGivenAPersonWithAGenderOfFemale()
{
    var personId = Guid.NewGuid();
    var gender = "F";
    var person = new Person(personId, gender);

    var id = Guid.NewGuid();
    var offer1 = new Offer1(id,"Offer1");
    Assert.False(offer1.IsEligible(person));
}

Ten test jednostkowy się powiódł. Jednak nie powiedzie się, jeśli „Oferta1” zostanie zaoferowana kobietom w przyszłości.

Czy można powiedzieć, że jeśli zmienia się logika biznesowa oferująca 1, to test jednostkowy musi się zmienić. Należy pamiętać, że w niektórych przypadkach (w przypadku niektórych ofert) logika biznesowa jest zmieniana w bazie danych w następujący sposób:

update Offers set Gender='M' where offer=1;

aw niektórych przypadkach w modelu domeny takim jak ten:

if (Gender=Gender.Male)
{
  //do something
}

Należy również pamiętać, że w niektórych przypadkach logika domeny oferująca zmiany regularnie się zmienia, a w niektórych przypadkach nie.

w0051977
źródło
2
Pomyśl z innej strony: czy chcesz mieć testy, które nie zawiodą, gdy zmienisz logikę w testowanym systemie?
Fabio,

Odpowiedzi:

77

To nie jest kruche w zwykłym tego słowa znaczeniu. Test jednostkowy jest uważany za kruchy, jeśli psuje się z powodu zmian implementacyjnych, które nie wpływają na testowane zachowanie. Ale jeśli sama logika biznesowa ulegnie zmianie, test tej logiki powinien się przerwać.

To powiedziawszy, jeśli logika biznesowa rzeczywiście często się zmienia, być może niewłaściwe jest zakodowanie oczekiwań w testach jednostkowych. Zamiast tego możesz przetestować, czy konfiguracje w bazie danych wpływają na oferty zgodnie z oczekiwaniami.

Nazwa testu Returns False When Given A Person With A Gender Of Femalenie opisuje reguły biznesowej. Reguła biznesowa byłaby podobna Offers Applicable to M should not be applied to persons of gender F.

Możesz więc napisać test, który potwierdzi, że jeśli oferta jest zdefiniowana jako mająca zastosowanie tylko do osób typu M, wówczas osoba typu F nie zostanie wskazana jako kwalifikująca się do niej. Ten test zapewni logikę, nawet jeśli zmieni się konfiguracja określonych ofert.

JacquesB
źródło
@JaquesB, to nie byłby test jednostkowy? czy byłoby to? Uważam, że byłby to test integracyjny, gdyby baza danych była zaangażowana. Czy to prawda? Czy mówisz, że nie używaj testów jednostkowych, jeśli logika biznesowa bardzo się zmienia?
w0051977,
@ w0051977: Zależy jak piszesz test. Jeśli test obejmuje faktyczną zmianę zmiany czegoś w bazie danych, byłby to test integracyjny.
JacquesB
3
@ w0051977 lepszy pomysł - nie pozwól, aby repozytorium było zależnością komponentu odpowiedzialnego za wdrażanie reguł biznesowych. Mają koordynację wyższego poziomu, która wywołuje repozytorium, a następnie wywołuje reguły biznesowe. Teraz możesz w jednostce przetestować reguły biznesowe w izolacji.
Ant P
5
@ w0051977 oczywiście, że tak - testy określają zachowanie. Jeśli reguły rządzące zachowaniem komponentu ulegną zmianie, testy muszą się zmienić, aby odzwierciedlić zmianę zachowania. To, czego nie trzeba zmieniać, to testy określające zachowania inne niż to, co się zmienia. Jeśli zachowanie jest określone przez bazę danych, test obejmujący inny kod jest z natury niezwiązany i nie powinien wymagać zmiany, chyba że logika tej bazy danych jest objęta zakresem testu. Ten zakres jest do zdefiniowania, a semantyka, czy jest to test jednostkowy czy test integracyjny, nie jest tak naprawdę ważna.
Ant P
3
@ w0051977 nieco rozszerzając ten pomysł, jeśli logika biznesowa ulegnie zmianie lub błąd zostanie naprawiony, a testy nie wymagają dostosowania, jest to znak, że testy nie obejmują wystarczających przypadków i powinny zostać ogólnie rozszerzone.
Morgen
14

Gdy właściwość jest zdefiniowana w produkcyjnej bazie danych (lub klonie do testowania), nie jest to test jednostkowy . Test jednostkowy sprawdza jednostkę pracy i nie wymaga określonego stanu zewnętrznego do pracy. Zakłada się, że Offer1baza danych jest zdefiniowana jako oferta tylko dla mężczyzn. To jest stan zewnętrzny. Jest to więc bardziej test integracyjny , w szczególności test systemowy lub test akceptacyjny . Zauważ, że testy akceptacyjne często nie są wykonywane skryptami (nie są uruchamiane w ramach testów, ale wykonywane ręcznie przez ludzi).

Gdy właściwość jest zdefiniowana w modelu domeny z ifinstrukcją, ten sam test jest testem jednostkowym. I może być kruche. Ale prawdziwym problemem jest to, że kod jest kruchy. Zasadniczo kod będzie bardziej odporny, jeśli zachowanie biznesowe można skonfigurować, a nie na stałe. Ponieważ wdrożenie w pośpiechu w celu naprawienia małego błędu kodowania powinno być rzadkie. Ale wymagania biznesowe zmieniające się bez powiadomienia to tylko wtorek (coś, co dzieje się co tydzień).

Do uruchomienia testu możesz użyć szkieletu testu jednostkowego. Jednak ramy testów jednostkowych nie ograniczają się do uruchamiania testów jednostkowych. Mogą również przeprowadzać testy integracyjne.

Gdybyś pisał test jednostkowy, stworzyłbyś jedno personi offer1od podstaw, bez polegania na stanie bazy danych. Coś jak

[Fact]
public void ReturnsFalseWhenGivenAPersonWithAGenderOfFemale()
{
    var personId = Guid.NewGuid();
    var gender = "F";
    var person = new Person(personId, gender);

    var id = Guid.NewGuid();
    var offer1 = new Offer1(id, "ReturnsFalseWhenGivenAPersonWithAGenderOfFemale");
    offer1.markLimitedToGender("M");

    Assert.False(offer1.IsEligible(person));
}

Pamiętaj, że nie zmienia się to w zależności od logiki biznesowej. Nie twierdzenie, że offer1odrzuca kobiety. To offer1rodzaj oferty, która odrzuca kobiety.

Możesz utworzyć i skonfigurować bazę danych w ramach testu. W języku C # przy użyciu NUnit lub JUnit w Javie można ustawić bazę danych w Setupmetodzie. Prawdopodobnie twoja struktura testu ma podobne pojęcie. W tej metodzie można wstawiać rekordy do bazy danych za pomocą SQL.

Jeśli trudno jest napisać kod, który zastępuje testową bazę danych produkcyjną bazą danych, brzmi to jak słabość testowania w aplikacji. Do testowania lepiej byłoby użyć czegoś takiego jak wstrzyknięcie zależności, które pozwala na podstawienie. Następnie możesz napisać testy, które są niezależne od obecnych reguł biznesowych.

Zaletą tego jest to, że właścicielowi firmy (niekoniecznie właścicielowi firmy, a bardziej osobie odpowiedzialnej za ten produkt w hierarchii korporacyjnej) często łatwiej jest bezpośrednio skonfigurować reguły biznesowe. Ponieważ jeśli masz tego rodzaju ramy techniczne, łatwo jest zezwolić właścicielowi firmy na skorzystanie z interfejsu użytkownika (UI) w celu skonfigurowania oferty. Właściciel firmy wybierze ograniczenie w interfejsie użytkownika i wyda markLimitedToGender("M")połączenie. Następnie, gdy oferta zostanie utrwalona w bazie danych, będzie ją przechowywać. Ale nie musisz przechowywać oferty, aby z niej skorzystać. Twoje testy mogą więc stworzyć i skonfigurować ofertę, która nie istnieje w bazie danych.

W systemie zgodnie z opisem właściciel firmy musiałby przesłać zapytanie do grupy technicznej, która wydałaby odpowiedni kod SQL i zaktualizowałaby testy. Lub grupa techniczna musi edytować kod i testy (lub testy, a następnie kod). To wydaje się dość ciężkie podejście. Możesz to zrobić. Ale twoje oprogramowanie (nie tylko testy) byłoby mniej kruche, gdybyś nie musiał tego robić.

TL; DR : możesz pisać testy w ten sposób, ale lepiej jest pisać oprogramowanie, abyś nie musiał tego robić.

mdfst13
źródło
Wolę poprawić niektóre drobne szczegóły w twojej odpowiedzi. Sprawdź, czy dobrze zrozumiałem twoje intencje.
Doc Brown
W oryginalnym poście nic nie wskazuje na zaangażowanie bazy danych. Twierdzenie, że zakłada, że ​​oferta1 jest już w bazie danych, jest dziwne.
Winston Ewert
2
@WinstonEwert: istnieje wyraźne wskazanie, że musisz uważniej przeczytać pytanie. Nie zdawałem sobie z tego sprawy przy pierwszym czytaniu, ale tak właśnie mówi OP.
Doc Brown,
@ mdfst13, przepraszam, że tego nie zauważyłem. Jednak OP mówi, że warunki są czasami w bazie danych, a czasem w modelu domeny. Twoja odpowiedź jest idealna w pierwszym przypadku, a w drugim bez szacunku. Jeśli zredagujesz swoją odpowiedź, aby wyjaśnić ten punkt, usunę moje pochopne głosowanie.
Winston Ewert,