Czy oczekiwane wyniki testu jednostkowego powinny być zakodowane na stałe, czy też mogą zależeć od zainicjowanych zmiennych? Czy wyniki zapisane na stałe lub obliczone zwiększają ryzyko wprowadzenia błędów w teście jednostkowym? Czy są jeszcze inne czynniki, których nie wziąłem pod uwagę?
Na przykład, który z tych dwóch formatów jest bardziej niezawodny?
[TestMethod]
public void GetPath_Hardcoded()
{
MyClass target = new MyClass("fields", "that later", "determine", "a folder");
string expected = "C:\\Output Folder\\fields\\that later\\determine\\a folder";
string actual = target.GetPath();
Assert.AreEqual(expected, actual,
"GetPath should return a full directory path based on its fields.");
}
[TestMethod]
public void GetPath_Softcoded()
{
MyClass target = new MyClass("fields", "that later", "determine", "a folder");
string expected = "C:\\Output Folder\\" + string.Join("\\", target.Field1, target.Field2, target.Field3, target.Field4);
string actual = target.GetPath();
Assert.AreEqual(expected, actual,
"GetPath should return a full directory path based on its fields.");
}
EDYCJA 1: Czy w odpowiedzi na odpowiedź DXM opcja 3 jest preferowanym rozwiązaniem?
[TestMethod]
public void GetPath_Option3()
{
string field1 = "fields";
string field2 = "that later";
string field3 = "determine";
string field4 = "a folder";
MyClass target = new MyClass(field1, field2, field3, field4);
string expected = "C:\\Output Folder\\" + string.Join("\\", field1, field2, field3, field4);
string actual = target.GetPath();
Assert.AreEqual(expected, actual,
"GetPath should return a full directory path based on its fields.");
}
c#
unit-testing
Hand-E-Food
źródło
źródło
Odpowiedzi:
Myślę, że obliczona oczekiwana wartość daje bardziej solidne i elastyczne przypadki testowe. Również poprzez użycie dobrych nazw zmiennych w wyrażeniu, które obliczają oczekiwany wynik, jest o wiele bardziej jasne, skąd ten oczekiwany wynik pochodzi w pierwszej kolejności.
Powiedziawszy to, w twoim konkretnym przykładzie NIE ufam metodzie „Softcoded”, ponieważ używa ona twojego SUT (testowanego systemu) jako danych wejściowych do twoich obliczeń. Jeśli w MyClass występuje błąd, w którym pola nie są poprawnie przechowywane, test faktycznie się powiedzie, ponieważ podczas obliczania oczekiwanej wartości użyjemy niewłaściwego ciągu, podobnie jak target.GetPath ().
Moją sugestią byłoby obliczenie oczekiwanej wartości tam, gdzie ma to sens, ale upewnij się, że obliczenie nie zależy od żadnego kodu z samego SUT.
W odpowiedzi na aktualizację OP na moją odpowiedź:
Tak, w oparciu o moją wiedzę, ale nieco ograniczone doświadczenie w wykonywaniu TDD, wybrałbym opcję nr 3.
źródło
Co jeśli kod był następujący:
Twój drugi przykład nie złapie błędu, ale pierwszy przykład.
Ogólnie rzecz biorąc, odradzam programowanie miękkie, ponieważ może ukrywać błędy. Na przykład:
Czy potrafisz dostrzec problem? Nie popełniłbyś tego samego błędu w wersji zakodowanej na stałe. Trudniej jest uzyskać poprawne obliczenia niż wartości zakodowane na stałe. Dlatego wolę pracować z wartościami zakodowanymi na stałe niż z kodami programowanymi.
Ale są wyjątki. Co zrobić, jeśli Twój kod musi działać w systemie Windows i Linux? Ścieżka musi być nie tylko inna, ale musi także używać różnych separatorów ścieżek! Obliczanie ścieżki za pomocą funkcji, które wyodrębniają różnicę między, może mieć sens w tym kontekście.
źródło
Moim zdaniem obie twoje sugestie są mniej niż idealne. Idealny sposób to zrobić:
Innymi słowy, test powinien działać wyłącznie na podstawie danych wejściowych i wyjściowych obiektu, a nie na podstawie stanu wewnętrznego obiektu. Obiekt należy traktować jak czarną skrzynkę. (Nie lekceważę innych problemów, takich jak niewłaściwość użycia łańcucha.Join zamiast Path.Combine, ponieważ jest to tylko przykład.)
źródło
target.Dispose(); Assert.IsTrue(target.IsDisposed);
(bardzo prosty przykład)Dyskusja obejmuje dwa aspekty:
1. Używanie samego obiektu docelowego w przypadku testowym
Pierwsze pytanie brzmi: czy należy użyć samej klasy, aby polegać i wykonywać część pracy w testowym odcinku testowym? - Odpowiedź brzmi NIE, ponieważ ogólnie rzecz biorąc, nigdy nie powinieneś zakładać się o testowany kod. Jeśli nie zostanie to wykonane poprawnie, z czasem błędy stają się odporne na niektóre testy jednostkowe.
2. Twarde kodowanie
Czy powinieneś ciężko kodować ? Ponownie odpowiedź brzmi: nie . ponieważ jak każde oprogramowanie - twarde kodowanie informacji staje się trudne, gdy rzeczy ewoluują. Na przykład, jeśli chcesz ponownie zmodyfikować powyższą ścieżkę, musisz napisać dodatkową jednostkę lub kontynuować modyfikację. Lepszym sposobem jest utrzymanie daty wprowadzania i oceny na podstawie oddzielnej konfiguracji, którą można łatwo dostosować.
na przykład tutaj chciałbym skorygować kod testowy.
źródło
Istnieje wiele możliwych koncepcji, podanych kilka przykładów, aby zobaczyć różnicę
Podsumowując: Ogólnie rzecz biorąc, twój pierwszy właśnie zakodowany test ma dla mnie sens, ponieważ jest prosty, od razu do rzeczy itp. Jeśli zbyt wiele razy zaczniesz kodować ścieżkę, po prostu umieść ją w metodzie konfiguracji.
Aby uzyskać więcej przyszłych testów strukturalnych, poszedłbym sprawdzić źródła danych, abyś mógł dodać więcej wierszy danych, jeśli potrzebujesz więcej sytuacji testowych.
źródło
Nowoczesne frameworki testowe umożliwiają dostarczanie parametrów do metody. Wykorzystałbym te:
Moim zdaniem ma to kilka zalet:
źródło