Поделиться через


Начало работы с Live Unit Testing

Если включить Live Unit Testing в решении Visual Studio, он визуально отображает покрытие тестов и состояние тестов. Live Unit Testing также динамически выполняет тесты при изменении кода и немедленно уведомляет вас о том, когда изменения вызывают сбой тестов.

Live Unit Testing можно использовать для тестирования решений, предназначенных для .NET Framework, .NET Core или .NET 5+. В этом руководстве вы узнаете, как использовать Live Unit Testing, создав простую библиотеку классов, предназначенную для .NET, и вы создадите проект MSTest, предназначенный для тестирования .NET.

Полное решение C# можно скачать из репозитория MicrosoftDocs/visualstudio-docs на GitHub.

Предпосылки

Для этого руководства необходимо, чтобы у вас была установлена версия Visual Studio Enterprise с рабочей нагрузкой разработки .NET для рабочего стола.

Создание решения и проекта библиотеки классов

Начните с создания решения Visual Studio с именем UtilityLibraries, состоящего из одного проекта библиотеки классов .NET, StringLibrary.

Решение — это просто контейнер для одного или нескольких проектов. Чтобы создать пустое решение, откройте Visual Studio и выполните следующие действия:

  1. >Выберите Файл>Новый проект в меню верхнего уровня Visual Studio.

  2. Введите решение в поле поиска шаблона и выберите шаблон "Пустое решение ". Присвойте проекту utilityLibraries имя.

  3. Завершите создание решения.

Теперь, когда вы создали решение, вы создадите библиотеку классов с именем StringLibrary, которая содержит ряд методов расширения для работы со строками.

  1. В обозревателе решений щелкните правой кнопкой мыши решение UtilityLibraries и выберите "Добавить>новый проект".

  2. Введите библиотеку классов в поле поиска шаблона и выберите шаблон библиотеки классов , предназначенный для .NET или .NET Standard. Нажмите кнопку Далее.

  3. Назовите проект StringLibrary.

  4. Нажмите кнопку "Создать" , чтобы создать проект.

  5. Замените весь существующий код в редакторе кода следующим кодом:

    using System;
    
    namespace UtilityLibraries
    {
        public static class StringLibrary
        {
            public static bool StartsWithUpper(this string s)
            {
                if (String.IsNullOrWhiteSpace(s))
                    return false;
    
                return Char.IsUpper(s[0]);
            }
    
            public static bool StartsWithLower(this string s)
            {
                if (String.IsNullOrWhiteSpace(s))
                    return false;
    
                return Char.IsLower(s[0]);
            }
    
            public static bool HasEmbeddedSpaces(this string s)
            {
                foreach (var ch in s.Trim())
                {
                    if (ch == ' ')
                        return true;
                }
                return false;
            }
        }
    }
    

    StringLibrary имеет три статических метода:

    • StartsWithUpper возвращает значение true , если строка начинается с символа верхнего регистра; в противном случае возвращается false.

    • StartsWithLower возвращает значение true , если строка начинается с нижнего регистра; в противном случае возвращается false.

    • HasEmbeddedSpaces возвращает значение true , если строка содержит внедренный символ пробела; в противном случае возвращается false.

  6. Выберите Сборка>Построить решение в меню Visual Studio верхнего уровня. Сборка должна завершиться успешно.

Создание тестового проекта

Следующим шагом является создание проекта модульного теста для тестирования библиотеки StringLibrary. Создайте модульные тесты, выполнив следующие действия.

  1. В обозревателе решений щелкните правой кнопкой мыши решение UtilityLibraries и выберите "Добавить>новый проект".

  2. Введите модульный тест в поле поиска шаблона, выберите C# в качестве языка, а затем выберите шаблон MSTest Unit Test для .NET. Нажмите кнопку Далее.

    Замечание

    В Visual Studio 2019 версии 16.9 имя шаблона проекта MSTest — проект модульного тестирования.

  3. Присвойте проекту имя StringLibraryTests и нажмите кнопку "Далее".

  4. Выберите рекомендуемую целевую платформу или .NET 8, а затем выберите Создать.

    Замечание

    В этом руководстве по началу работы используется Live Unit Testing с платформой тестирования MSTest. Также можно использовать платформы тестирования xUnit и NUnit.

  5. Проект модульного теста не может автоматически получить доступ к библиотеке классов, которую он тестирует. Вы предоставляете тестовой библиотеке доступ, добавив ссылку на проект библиотеки классов. Для этого щелкните проект правой StringLibraryTests кнопкой мыши и выберите "Добавить>ссылку на проект". В диалоговом окне диспетчера ссылок убедитесь, что выбрана вкладка решения и выберите проект StringLibrary, как показано на следующем рисунке.

    Диалоговое окно диспетчера ссылок

  6. Замените стандартный код модульного теста, предоставленный шаблоном, следующим кодом:

    using System;
    using Microsoft.VisualStudio.TestTools.UnitTesting;
    using UtilityLibraries;
    
    namespace StringLibraryTest
    {
        [TestClass]
        public class UnitTest1
        {
            [TestMethod]
            public void TestStartsWithUpper()
            {
                // Tests that we expect to return true.
                string[] words = { "Alphabet", "Zebra", "ABC", "Αθήνα", "Москва" };
                foreach (var word in words)
                {
                    bool result = word.StartsWithUpper();
                    Assert.IsTrue(result,
                                  $"Expected for '{word}': true; Actual: {result}");
                }
            }
    
            [TestMethod]
            public void TestDoesNotStartWithUpper()
            {
                // Tests that we expect to return false.
                string[] words = { "alphabet", "zebra", "abc", "αυτοκινητοβιομηχανία", "государство",
                                   "1234", ".", ";", " " };
                foreach (var word in words)
                {
                    bool result = word.StartsWithUpper();
                    Assert.IsFalse(result,
                                   $"Expected for '{word}': false; Actual: {result}");
                }
            }
    
            [TestMethod]
            public void DirectCallWithNullOrEmpty()
            {
                // Tests that we expect to return false.
                string[] words = { String.Empty, null };
                foreach (var word in words)
                {
                    bool result = StringLibrary.StartsWithUpper(word);
                    Assert.IsFalse(result,
                                   $"Expected for '{(word == null ? "<null>" : word)}': " +
                                   $"false; Actual: {result}");
                }
            }
        }
    }
    
  7. Сохраните проект, выбрав значок "Сохранить " на панели инструментов.

    Так как код модульного теста содержит некоторые символы, отличные от ASCII, вы увидите следующее диалоговое окно, чтобы предупредить, что некоторые символы будут потеряны, если сохранить файл в формате ASCII по умолчанию.

  8. Нажмите кнопку "Сохранить с другой кодировкой ".

    Выбор кодировки файла

  9. В раскрывающемся списке параметров кодирования диалогового окна "Параметры предварительного сохранения" выберите Юникод (UTF-8 без подписи) — Codepage 65001, как показано на следующем рисунке:

    Выбор кодировки UTF-8

  10. Скомпилируйте проект модульного теста, выбрав Сборка>Перестроить решение в меню Visual Studio верхнего уровня.

Вы создали библиотеку классов, а также некоторые модульные тесты для него. Теперь вы завершили предварительные действия, необходимые для использования Live Unit Testing.

Включение Динамического модульного тестирования

До сих пор, хотя вы написали тесты для библиотеки классов StringLibrary, вы не выполнили их. Live Unit Testing выполняет их автоматически после включения. Для этого сделайте следующее:

  1. При необходимости выберите окно редактора кода, содержащее код для StringLibrary. Это либо Class1.cs для проекта C#, либо Class1.vb для проекта Visual Basic. (Этот шаг позволяет визуально проверить результат тестов и степень охвата кода после включения Live Unit Testing.)

  2. Выберите "Живое>модульное тестирование>Запустить" в верхнем меню Visual Studio.

  3. Проверьте конфигурацию Live Unit Testing, убедившись, что корневой каталог репозитория содержит путь к исходным файлам для проекта служебной программы и тестового проекта. Нажмите кнопку "Далее " и " Готово".

  1. В окне Live Unit Testing выберите ссылку "Включить все тесты " (Кроме того, щелкните значок кнопки "Список воспроизведения ", а затем выберите StringLibraryTest, который выбирает все тесты под ним. Затем нажмите кнопку "Список воспроизведения ", чтобы выйти из режима редактирования.)

  2. Visual Studio перестроит проект и запустит Live Unit Test, который автоматически запускает все тесты.

После завершения выполнения тестов Live Unit Testing отображает как общие результаты, так и результат отдельных тестов. Кроме того, в окне редактора кода графически отображаются как покрытие тестового кода, так и результаты ваших тестов. Как показано на следующем рисунке, все три теста успешно выполнены. В нем также показано, что наши тесты охватывали все пути кода в методе StartsWithUpper , и все тесты успешно выполнялись (что обозначается зеленым флажоком "✓"). В заключение показывается, что ни один из других методов в StringLibrary не имеет покрытия кода, что обозначено синей линией "➖".

Окно обозревателя динамических тестов и редактора кода после запуска Live Unit Testing

Вы также можете получить более подробную информацию о охвате теста и результатах теста, выбрав в окне редактора кода определенный значок покрытия кода. Чтобы изучить эту информацию, сделайте следующее:

  1. Щелкните зеленую галочку в строке с надписью if (String.IsNullOrWhiteSpace(s)) в методе StartsWithUpper. Как показано на следующем рисунке, Live Unit Testing указывает, что три теста охватывают эту строку кода и что все успешно выполнены.

    Покрытие кода для условной инструкции if

  2. Щелкните зеленую галочку на строке, которая содержит return Char.IsUpper(s[0]) в методе StartsWithUpper . Как показано на следующем рисунке, Live Unit Testing указывает, что только два теста охватывают такую строку кода и все успешно выполнены.

    Покрытие кода для инструкции return

Основная проблема, которую обнаруживает Live Unit Testing, — неполное покрытие кода. К нему следует обратиться в следующем разделе.

Расширение тестового покрытия

В этом разделе вы расширите модульные тесты для метода StartsWithLower. В это время Live Unit Testing будет динамически тестировать ваш код.

Чтобы расширить охват кода методом StartsWithLower , сделайте следующее:

  1. Добавьте следующие TestStartsWithLower методы и TestDoesNotStartWithLower методы в файл тестового исходного кода проекта:

    // Code to add to UnitTest1.cs
    [TestMethod]
    public void TestStartsWithLower()
    {
        // Tests that we expect to return true.
        string[] words = { "alphabet", "zebra", "abc", "αυτοκινητοβιομηχανία", "государство" };
        foreach (var word in words)
        {
            bool result = word.StartsWithLower();
            Assert.IsTrue(result,
                          $"Expected for '{word}': true; Actual: {result}");
        }
    }
    
    [TestMethod]
    public void TestDoesNotStartWithLower()
    {
        // Tests that we expect to return false.
        string[] words = { "Alphabet", "Zebra", "ABC", "Αθήνα", "Москва",
                           "1234", ".", ";", " "};
        foreach (var word in words)
        {
            bool result = word.StartsWithLower();
            Assert.IsFalse(result,
                           $"Expected for '{word}': false; Actual: {result}");
        }
    }
    
  2. Измените DirectCallWithNullOrEmpty метод, добавив следующий код сразу после вызова Microsoft.VisualStudio.TestTools.UnitTesting.Assert.IsFalse метода.

    // Code to add to UnitTest1.cs
    result = StringLibrary.StartsWithLower(word);
    Assert.IsFalse(result,
                   $"Expected for '{(word == null ? "<null>" : word)}': " +
                   $"false; Actual: {result}");
    
  3. Live Unit Testing автоматически выполняет новые и измененные тесты при изменении исходного кода. Как показано на следующем рисунке, все тесты, включая два добавленных вами и один измененный вами, успешно выполнены.

    Обозреватель динамических тестов после расширения охвата тестов

  4. Перейдите в окно, содержащее исходный код класса StringLibrary. Live Unit Testing теперь показывает, что покрытие кода теперь охватывает метод StartsWithLower.

    Покрытие кода для метода StartsWithLower

В некоторых случаях успешные тесты в обозревателе тестов могут быть серыми. Это означает, что тест выполняется в настоящее время или что тест не выполняется повторно, так как не было изменений кода, которые повлияют на тест после последнего выполнения.

До сих пор все наши тесты завершились успешно. В следующем разделе мы рассмотрим, как справиться с ошибкой теста.

Обработка тестового сбоя

В этом разделе описано, как использовать Live Unit Testing для выявления, устранения неполадок и устранения сбоев тестов. Это можно сделать, расширив охват теста методом HasEmbeddedSpaces .

  1. Добавьте следующий метод в тестовый файл:

    [TestMethod]
    public void TestHasEmbeddedSpaces()
    {
        // Tests that we expect to return true.
        string[] phrases = { "one car", "Name\u0009Description",
                             "Line1\nLine2", "Line3\u000ALine4",
                             "Line5\u000BLine6", "Line7\u000CLine8",
                             "Line0009\u000DLine10", "word1\u00A0word2" };
        foreach (var phrase in phrases)
        {
            bool result = phrase.HasEmbeddedSpaces();
            Assert.IsTrue(result,
                          $"Expected for '{phrase}': true; Actual: {result}");
        }
    }
    
  2. При выполнении теста Live Unit Testing указывает, что TestHasEmbeddedSpaces метод завершился сбоем, как показано на следующем рисунке:

    Обозреватель динамических тестов, сообщающий о неудачном тесте

  3. Выберите окно, отображающее код библиотеки. Live Unit Testing расширило охват кода для HasEmbeddedSpaces метода. Он также сообщает о сбое теста, добавив красный "🞩" в строки, охваченные неудачными тестами.

  4. Наведите указатель мыши на строку с сигнатурой HasEmbeddedSpaces метода. Live Unit Testing отображает подсказку, которая сообщает, что метод рассматривается одним тестом, как показано на следующем рисунке:

    Сведения о динамическом модульном тестировании для неудачного теста

  5. Выберите неудачный тест TestHasEmbeddedSpaces. Live Unit Testing предоставляет несколько вариантов, таких как выполнение всех тестов и отладка всех тестов, как показано на следующем рисунке:

    Варианты Динамического модульного тестирования для неудачного теста

  6. Выберите "Отладка всех", чтобы выполнить отладку неудачного теста.

  7. Visual Studio выполняет тест в режиме отладки.

    Тест назначает каждую строку в массиве переменной с именем phrase и передает ее методу HasEmbeddedSpaces . Выполнение программы приостанавливается и вызывается отладчик, когда условие false утверждения срабатывает впервые. Диалоговое окно исключения, которое приводит к неожиданному значению в вызове Microsoft.VisualStudio.TestTools.UnitTesting.Assert.IsTrue метода, отображается на следующем рисунке.

    Диалоговое окно исключения Live Unit Testing

    Кроме того, все средства отладки, предоставляемые Visual Studio, доступны для устранения неполадок с неудачным тестом, как показано на следующем рисунке:

    Средства отладки Visual Studio

    Обратите внимание, что в окне Autos значение переменной phrase — "Name\tDescription", которое является вторым элементом массива. Метод теста ожидает, что HasEmbeddedSpaces вернет true при передаче этой строки; вместо этого возвращается false. Очевидно, что он не распознает "\t", символ табуляции, как вставленный пробел.

  8. Нажмите кнопку"Продолжить>", нажмите клавишу F5 или нажмите кнопку "Продолжить" на панели инструментов, чтобы продолжить выполнение тестовой программы. Так как произошло необработанное исключение, тест завершается. Это обеспечивает достаточно сведений о предварительном расследовании ошибки. Либо TestHasEmbeddedSpaces (подпрограмма тестирования) сделала неверное предположение, либо HasEmbeddedSpaces неправильно распознает все внедренные пробелы.

  9. Чтобы диагностировать и исправить проблему, начните с StringLibrary.HasEmbeddedSpaces метода. Просмотрите сравнение в методе HasEmbeddedSpaces . Он считает встроенный пробел символом U+0020. Однако стандарт Юникода содержит ряд других символов пространства. Это означает, что код библиотеки неправильно протестирован для символа пробела.

  10. Замените сравнение равенства вызовом System.Char.IsWhiteSpace метода:

    if (Char.IsWhiteSpace(ch))
    
  11. Live Unit Testing автоматически повторно выполняет тестовый метод, который завершился ошибкой.

    Live Unit Testing отображает обновленные результаты, которые также отображаются в окне редактора кода.