Przewodnik: programowanie oparte na testach przy użyciu Eksploratora testów
Tworzenie testów jednostkowych w celu zapewnienia prawidłowego działania kodu przez przyrostowe zmiany kodu. Istnieje kilka struktur, których można użyć do pisania testów jednostkowych, w tym niektórych opracowanych przez inne firmy. Niektóre struktury testowe są przeznaczone do testowania w różnych językach lub platformach. Eksplorator testów udostępnia jeden interfejs dla testów jednostkowych w dowolnej z tych platform. Aby uzyskać więcej informacji na temat Eksploratora testów, zobacz Uruchamianie testów jednostkowych za pomocą Eksploratora testów i Eksploratora testów — często zadawane pytania.
W tym przewodniku pokazano, jak opracować przetestowaną metodę w języku C# przy użyciu programu Microsoft Test Framework (MSTest). Można go łatwo dostosować do innych języków lub innych struktur testowych, takich jak NUnit. Aby uzyskać więcej informacji, zobacz Instalowanie platform testów jednostkowych innych firm.
Tworzenie testu i generowanie kodu
Utwórz projekt biblioteki klas języka C# dla platformy .NET lub .NET Standard. Ten projekt będzie zawierać kod, który chcemy przetestować. Nadaj projektowi nazwę MyMath.
W tym samym rozwiązaniu dodaj nowy projekt testowy MSTest dla platformy .NET.
W programie Visual Studio 2019 w wersji 16.9 nazwa szablonu projektu MSTest to Unit Test Project.
Nadaj projektowi testowe nazwę MathTests.
Napisz prostą metodę testową, która weryfikuje wynik uzyskany dla określonego danych wejściowych. Dodaj następujący kod do
UnitTest1
klasy:[TestMethod] public void BasicRooterTest() { // Create an instance to test: Rooter rooter = new Rooter(); // Define a test input and output value: double expectedResult = 2.0; double input = expectedResult * expectedResult; // Run the method under test: double actualResult = rooter.SquareRoot(input); // Verify the result: Assert.AreEqual(expectedResult, actualResult, delta: expectedResult / 100); }
Generowanie typu na podstawie kodu testowego.
Umieść kursor na
Rooter
, a następnie z menu żarówki wybierz pozycję Wygeneruj typ "Rooter"> Wygeneruj nowy typ.W oknie dialogowym Generowanie typu ustaw wartość Project na MyMath, projekt biblioteki klas, a następnie wybierz przycisk OK.
Wygeneruj metodę na podstawie kodu testowego. Umieść kursor na
SquareRoot
, a następnie z menu żarówki wybierz pozycję Generuj metodę "Rooter.SquareRoot".Uruchom test jednostkowy.
Otwórz Eksploratora testów.
Aby otworzyć Eksploratora testów z menu Test , wybierz pozycję Eksplorator testów.
Aby otworzyć Eksploratora testów z menu Test, wybierz pozycję Eksplorator testów systemu Windows>.
W Eksploratorze testów wybierz przycisk Uruchom wszystko , aby uruchomić test.
Rozwiązanie jest kompilowanie, a testy są uruchamiane i kończą się niepowodzeniem.
Wybierz nazwę testu.
Szczegóły testu są wyświetlane w okienku Podsumowanie szczegółów testu.
Wybierz górny link w obszarze Ślad stosu, aby przejść do lokalizacji, w której test zakończył się niepowodzeniem.
W tym momencie utworzono test i wycinkę, którą można zmodyfikować, tak aby test przebiegł pomyślnie.
Weryfikowanie zmiany kodu
W pliku Class1.cs popraw kod elementu
SquareRoot
:public double SquareRoot(double input) { return input / 2; }
W Eksploratorze testów wybierz pozycję Uruchom wszystko.
Rozwiązanie zostanie skompiluje, a test przebiegnie i przejdzie pomyślnie.
Rozszerzanie zakresu danych wejściowych
Aby zwiększyć pewność, że kod działa we wszystkich przypadkach, dodaj testy, które próbują uzyskać szerszy zakres wartości wejściowych.
Napiwek
Unikaj zmiany istniejących testów, które przeszły. Zamiast tego dodaj nowe testy. Zmień istniejące testy tylko wtedy, gdy zmienią się wymagania użytkownika. Te zasady pomagają upewnić się, że nie utracisz istniejących funkcji podczas pracy nad rozszerzeniem kodu.
W klasie testowej dodaj następujący test, który próbuje dawać zakres wartości wejściowych:
[TestMethod] public void RooterValueRange() { // Create an instance to test. Rooter rooter = new Rooter(); // Try a range of values. for (double expected = 1e-8; expected < 1e+8; expected *= 3.2) { RooterOneValue(rooter, expected); } } private void RooterOneValue(Rooter rooter, double expectedResult) { double input = expectedResult * expectedResult; double actualResult = rooter.SquareRoot(input); Assert.AreEqual(expectedResult, actualResult, delta: expectedResult / 1000); }
W Eksploratorze testów wybierz pozycję Uruchom wszystko.
Nowy test kończy się niepowodzeniem (chociaż pierwszy test nadal przechodzi). Aby znaleźć punkt awarii, wybierz test zakończony niepowodzeniem, a następnie przyjrzyj się szczegółom w okienku Podsumowanie szczegółów testu.
Sprawdź metodę testową, aby zobaczyć, co może być złe. Zmień kod w
SquareRoot
następujący sposób:public double SquareRoot(double input) { double result = input; double previousResult = -input; while (Math.Abs(previousResult - result) > result / 1000) { previousResult = result; result = result - (result * result - input) / (2 * result); } return result; }
W Eksploratorze testów wybierz pozycję Uruchom wszystko.
Oba testy są teraz przekazywane.
Dodawanie testów dla wyjątkowych przypadków
Dodaj nowy test dla ujemnych danych wejściowych:
[TestMethod] public void RooterTestNegativeInput() { Rooter rooter = new Rooter(); Assert.ThrowsException<ArgumentOutOfRangeException>(() => rooter.SquareRoot(-1)); }
W Eksploratorze testów wybierz pozycję Uruchom wszystko.
Metoda w pętli testowych i musi zostać anulowana ręcznie.
Wybierz pozycję Anuluj na pasku narzędzi Eksploratora testów.
Test zatrzymuje wykonywanie.
Napraw kod,
SquareRoot
dodając następującąif
instrukcję na początku metody:public double SquareRoot(double input) { if (input <= 0.0) { throw new ArgumentOutOfRangeException(); } ...
W Eksploratorze testów wybierz pozycję Uruchom wszystko.
Wszystkie testy kończą się powodzeniem.
Refaktoryzacja kodu testowego
Refaktoryzuj kod, ale nie zmieniaj testów.
Napiwek
Refaktoryzacja to zmiana, która ma na celu lepsze lub łatwiejsze zrozumienie kodu. Nie jest ona przeznaczona do zmiany zachowania kodu, dlatego testy nie są zmieniane.
Zalecamy wykonanie kroków refaktoryzacji niezależnie od kroków rozszerzających funkcjonalność. Utrzymywanie testów bez zmian zapewnia pewność, że podczas refaktoryzacji nie zostały przypadkowo wprowadzone usterki.
Zmień wiersz, który jest obliczany
result
w metodzieSquareRoot
w następujący sposób:public double SquareRoot(double input) { if (input <= 0.0) { throw new ArgumentOutOfRangeException(); } double result = input; double previousResult = -input; while (Math.Abs(previousResult - result) > result / 1000) { previousResult = result; result = (result + input / result) / 2; //was: result = result - (result * result - input) / (2*result); } return result; }
Wybierz pozycję Uruchom wszystko i sprawdź, czy wszystkie testy nadal przechodzą pomyślnie.