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

  1. 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.

  2. 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.

    New code and test projects

    New code and test projects

  3. 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);
    }
    
  4. Generowanie typu na podstawie kodu testowego.

    1. Umieść kursor na Rooter, a następnie z menu żarówki wybierz pozycję Wygeneruj typ "Rooter"> Wygeneruj nowy typ.

      Generate new type quick action

      Generate new type quick action

    2. W oknie dialogowym Generowanie typu ustaw wartość Project na MyMath, projekt biblioteki klas, a następnie wybierz przycisk OK.

      Generate Type dialog box in Visual Studio 2019

      Generate Type dialog box in Visual Studio 2019

  5. Wygeneruj metodę na podstawie kodu testowego. Umieść kursor na SquareRoot, a następnie z menu żarówki wybierz pozycję Generuj metodę "Rooter.SquareRoot".

  6. Uruchom test jednostkowy.

    1. 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>.

    2. W Eksploratorze testów wybierz przycisk Uruchom wszystko , aby uruchomić test.

    Rozwiązanie jest kompilowanie, a testy są uruchamiane i kończą się niepowodzeniem.

  7. Wybierz nazwę testu.

    Szczegóły testu są wyświetlane w okienku Podsumowanie szczegółów testu.

    Test Detail Summary in Test Explorer

    Test Detail Summary in Test Explorer

  8. 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

  1. W pliku Class1.cs popraw kod elementu SquareRoot:

    public double SquareRoot(double input)
    {
        return input / 2;
    }
    
  2. W Eksploratorze testów wybierz pozycję Uruchom wszystko.

    Rozwiązanie zostanie skompiluje, a test przebiegnie i przejdzie pomyślnie.

    Test Explorer showing a passing test

    Test Explorer showing a passing test

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.

  1. 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);
    }
    
  2. 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.

  3. 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;
    }
    
  4. W Eksploratorze testów wybierz pozycję Uruchom wszystko.

    Oba testy są teraz przekazywane.

Dodawanie testów dla wyjątkowych przypadków

  1. Dodaj nowy test dla ujemnych danych wejściowych:

    [TestMethod]
    public void RooterTestNegativeInput()
    {
        Rooter rooter = new Rooter();
        Assert.ThrowsException<ArgumentOutOfRangeException>(() => rooter.SquareRoot(-1));
    }
    
  2. W Eksploratorze testów wybierz pozycję Uruchom wszystko.

    Metoda w pętli testowych i musi zostać anulowana ręcznie.

  3. Wybierz pozycję Anuluj na pasku narzędzi Eksploratora testów.

    Test zatrzymuje wykonywanie.

  4. 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();
        }
        ...
    
  5. 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.

  1. Zmień wiersz, który jest obliczany result w metodzie SquareRoot 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;
    }
    
  2. Wybierz pozycję Uruchom wszystko i sprawdź, czy wszystkie testy nadal przechodzą pomyślnie.

    Test Explorer showing 3 passed tests

    Test Explorer showing 3 passed tests