Учебник. Тестирование библиотеки классов .NET с помощью .NET в Visual StudioTutorial: Test a .NET class library with .NET using Visual Studio

В этом руководстве показано, как автоматизировать модульное тестирование путем добавления тестового проекта в решение.This tutorial shows how to automate unit testing by adding a test project to a solution.

Предварительные требованияPrerequisites

Создание проекта модульного тестаCreate a unit test project

Модульные тесты обеспечивают автоматическое тестирование программного обеспечения во время разработки и публикации.Unit tests provide automated software testing during your development and publishing. MSTest — это одна из трех доступных для выбора платформ тестирования.MSTest is one of three test frameworks you can choose from. Другими являются xUnit и nUnit.The others are xUnit and nUnit.

  1. Запустите Visual Studio.Start Visual Studio.

  2. Откройте решениеClassLibraryProjects, созданное при работе со статьей Создание библиотеки классов .NET в Visual Studio.Open the ClassLibraryProjects solution you created in Create a .NET class library using Visual Studio.

  3. Добавьте в решение новый проект модульного теста с именем StringLibraryTest.Add a new unit test project named "StringLibraryTest" to the solution.

    1. Щелкните решение в обозревателе решений правой кнопкой мыши и выберите Добавить > Новый проект.Right-click on the solution in Solution Explorer and select Add > New project.

    2. На странице Добавить новый проект введите в поле поиска mstest.On the Add a new project page, enter mstest in the search box. Выберите C# или Visual Basic из списка языков, а затем — Все платформы из списка платформ.Choose C# or Visual Basic from the Language list, and then choose All platforms from the Platform list.

    3. Выберите шаблон Проект модульного теста и нажмите кнопку Далее.Choose the Unit Test Project template, and then choose Next.

    4. На странице Настроить новый проект введите StringLibraryTest в поле Имя проекта.On the Configure your new project page, enter StringLibraryTest in the Project name box. Нажмите кнопку Далее.Then choose Next.

    5. На странице Дополнительные сведения выберите .NET 5.0 (текущая) в поле Целевая платформа.On the Additional information page, select .NET 5.0 (Current) in the Target Framework box. Затем нажмите кнопку Создать.Then choose Create.

  4. Visual Studio создаст проект и откроет файл класса в окне кода с помощью следующего кода:Visual Studio creates the project and opens the class file in the code window with the following code. Если нужный язык не отображается, измените выбор языка в верхней части страницы.If the language you want to use is not shown, change the language selector at the top of the page.

    using Microsoft.VisualStudio.TestTools.UnitTesting;
    
    namespace StringLibraryTest
    {
        [TestClass]
        public class UnitTest1
        {
            [TestMethod]
            public void TestMethod1()
            {
            }
        }
    }
    
    Imports Microsoft.VisualStudio.TestTools.UnitTesting
    
    Namespace StringLibraryTest
        <TestClass>
        Public Class UnitTest1
            <TestMethod>
            Sub TestSub()
    
            End Sub
        End Class
    End Namespace
    

    Исходный код, созданный шаблоном модульного теста, выполняет следующие действия.The source code created by the unit test template does the following:

    При запуске модульного теста автоматически выполняются все методы теста, помеченные атрибутом [TestMethod], в тестовом классе, помеченном атрибутом [TestClass].Each method tagged with [TestMethod] in a test class tagged with [TestClass] is executed automatically when the unit test is run.

Добавление ссылки на проектAdd a project reference

Чтобы тестовый проект работал с классом StringLibrary, добавьте в проект StringLibraryTest ссылку на проект StringLibrary.For the test project to work with the StringLibrary class, add a reference in the StringLibraryTest project to the StringLibrary project.

  1. В обозревателе решений правой кнопкой мыши щелкните узел Зависимости в проекте StringLibraryTest и в контекстном меню выберите пункт Добавить ссылку на проект.In Solution Explorer, right-click the Dependencies node of the StringLibraryTest project and select Add Project Reference from the context menu.

  2. В диалоговом окне Диспетчер ссылок разверните узел Проекты и установите флажок рядом с пунктом StringLibrary.In the Reference Manager dialog, expand the Projects node, and select the box next to StringLibrary. Добавление ссылки на сборку StringLibrary позволяет компилятору находить методы StringLibrary во время компиляции проекта StringLibraryTest.Adding a reference to the StringLibrary assembly allows the compiler to find StringLibrary methods while compiling the StringLibraryTest project.

  3. Нажмите кнопку ОК.Select OK.

Добавление и выполнение методов модульного тестаAdd and run unit test methods

При запуске модульного теста Visual Studio выполняет каждый метод, помеченный атрибутом TestMethodAttribute, в классе, помеченном атрибутом TestClassAttribute.When Visual Studio runs a unit test, it executes each method that is marked with the TestMethodAttribute attribute in a class that is marked with the TestClassAttribute attribute. Метод теста завершается, когда происходит первый сбой или когда все тесты, содержащиеся в методе, будут успешно выполнены.A test method ends when the first failure is found or when all tests contained in the method have succeeded.

В самых распространенных тестах вызываются члены класса Assert.The most common tests call members of the Assert class. Многие методы утверждения (Assert) принимают по крайней мере два параметра, из которых один представляет ожидаемый результат теста, а второй — фактический результат теста.Many assert methods include at least two parameters, one of which is the expected test result and the other of which is the actual test result. Наиболее популярные из этих методов класса Assert перечислены в следующей таблице:Some of the Assert class's most frequently called methods are shown in the following table:

Методы утвержденияAssert methods ФункцияFunction
Assert.AreEqual Проверяет равенство двух значений или объектов.Verifies that two values or objects are equal. Утверждение не выполняется, если значения или объекты не равны.The assert fails if the values or objects aren't equal.
Assert.AreSame Проверяет, что две объектные переменные ссылаются на один и тот же объект.Verifies that two object variables refer to the same object. Утверждение не выполняется, если переменные ссылаются на разные объекты.The assert fails if the variables refer to different objects.
Assert.IsFalse Проверяет, что условие имеет значение false.Verifies that a condition is false. Утверждение не выполняется, если условие имеет значение true.The assert fails if the condition is true.
Assert.IsNotNull Проверяет, что объект не имеет значение null.Verifies that an object isn't null. Утверждение не выполняется, если объект является null.The assert fails if the object is null.

Вы можете также использовать метод Assert.ThrowsException в методе теста, чтобы указать тип исключения, которое он должен создавать.You can also use the Assert.ThrowsException method in a test method to indicate the type of exception it's expected to throw. Такой тест считается не выполненным, если заявленное исключение не было создано.The test fails if the specified exception isn't thrown.

Для тестирования метода StringLibrary.StartsWithUpper необходимо предоставить несколько строк, которые начинаются с символов верхнего регистра.In testing the StringLibrary.StartsWithUpper method, you want to provide a number of strings that begin with an uppercase character. Предполагается, что в этих случаях метод возвратит true, поэтому можно вызвать метод Assert.IsTrue.You expect the method to return true in these cases, so you can call the Assert.IsTrue method. Представьте также несколько строк, которые не начинаются с символов верхнего регистра.Similarly, you want to provide a number of strings that begin with something other than an uppercase character. Предполагается, что в этих случаях метод возвратит false, поэтому можно вызвать метод Assert.IsFalse.You expect the method to return false in these cases, so you can call the Assert.IsFalse method.

Так как ваш метод библиотеки обрабатывает строки, нам нужно проверить правильность обработки пустых строк (String.Empty) (так называется допустимая строка, которая не содержит символов и для которой свойство Length имеет значение 0) и строки null, которая не была инициализирована.Since your library method handles strings, you also want to make sure that it successfully handles an empty string (String.Empty), a valid string that has no characters and whose Length is 0, and a null string that hasn't been initialized. Метод StartsWithUpper можно вызвать напрямую как статический метод и передать ему один аргумент типа String.You can call StartsWithUpper directly as a static method and pass a single String argument. Или метод StartsWithUpper можно вызвать как метод расширения для переменной string, которой назначено значение null.Or you can call StartsWithUpper as an extension method on a string variable assigned to null.

Вы определите три метода, каждый из которых вызывает метод Assert для каждого элемента в массиве строк.You'll define three methods, each of which calls an Assert method for each element in a string array. Вы вызовете перегруженную версию метода, которая позволяет указать сообщение об ошибке, отображаемое в случае сбоя теста.You'll call a method overload that lets you specify an error message to be displayed in case of test failure. В этом сообщении определяется строка, вызвавшая сбой.The message identifies the string that caused the failure.

Создание методов теста:To create the test methods:

  1. В окне кода UnitTest1.cs или UnitTest1.vb замените отображаемый код на следующий текст:In the UnitTest1.cs or UnitTest1.vb code window, replace the code with the following code:

    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,
                           String.Format("Expected for '{0}': true; Actual: {1}",
                                         word, 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,
                           String.Format("Expected for '{0}': false; Actual: {1}",
                                         word, 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,
                           String.Format("Expected for '{0}': false; Actual: {1}",
                                         word == null ? "<null>" : word, result));
                }
            }
        }
    }
    
    Imports Microsoft.VisualStudio.TestTools.UnitTesting
    Imports UtilityLibraries
    
    Namespace StringLibraryTest
        <TestClass>
        Public Class UnitTest1
            <TestMethod>
            Public Sub TestStartsWithUpper()
                ' Tests that we expect to return true.
                Dim words() As String = {"Alphabet", "Zebra", "ABC", "Αθήνα", "Москва"}
                For Each word In words
                    Dim result As Boolean = word.StartsWithUpper()
                    Assert.IsTrue(result,
                           $"Expected for '{word}': true; Actual: {result}")
                Next
            End Sub
    
            <TestMethod>
            Public Sub TestDoesNotStartWithUpper()
                ' Tests that we expect to return false.
                Dim words() As String = {"alphabet", "zebra", "abc", "αυτοκινητοβιομηχανία", "государство",
                                   "1234", ".", ";", " "}
                For Each word In words
                    Dim result As Boolean = word.StartsWithUpper()
                    Assert.IsFalse(result,
                           $"Expected for '{word}': false; Actual: {result}")
                Next
            End Sub
    
            <TestMethod>
            Public Sub DirectCallWithNullOrEmpty()
                ' Tests that we expect to return false.
                Dim words() As String = {String.Empty, Nothing}
                For Each word In words
                    Dim result As Boolean = StringLibrary.StartsWithUpper(word)
                    Assert.IsFalse(result,
                           $"Expected for '{If(word Is Nothing, "<null>", word)}': false; Actual: {result}")
                Next
            End Sub
        End Class
    End Namespace
    

    Тест на символы верхнего регистра в методе TestStartsWithUpper включает заглавную греческую букву "альфа" (U+0391) и заглавную кириллическую букву "М" (U+041C).The test of uppercase characters in the TestStartsWithUpper method includes the Greek capital letter alpha (U+0391) and the Cyrillic capital letter EM (U+041C). Тест на символы нижнего регистра в методе TestDoesNotStartWithUpper включает строчную греческую букву "альфа" (U+03B1) и строчную кириллическую букву "г" (U+0433).The test of lowercase characters in the TestDoesNotStartWithUpper method includes the Greek small letter alpha (U+03B1) and the Cyrillic small letter Ghe (U+0433).

  2. В строке меню выберите Файл > Сохранить UnitTest1.cs как или Файл > Сохранить UnitTest1.vb как.On the menu bar, select File > Save UnitTest1.cs As or File > Save UnitTest1.vb As. В диалоговом окне Сохранить файл как щелкните стрелку рядом с кнопкой Сохранить и выберите вариант Сохранить с кодировкой.In the Save File As dialog, select the arrow beside the Save button, and select Save with Encoding.

    Диалоговое окно Сохранить файл как в Visual Studio

  3. В диалоговом окне Подтверждение сохранения нажмите кнопку Да, чтобы сохранить файл.In the Confirm Save As dialog, select the Yes button to save the file.

  4. В диалоговом окне Дополнительные параметры сохранения выберите в раскрывающемся списка Кодировка вариант Юникод (UTF-8, с сигнатурой), кодовая страница 65001 и нажмите кнопку ОК.In the Advanced Save Options dialog, select Unicode (UTF-8 with signature) - Codepage 65001 from the Encoding drop-down list and select OK.

    Диалоговое окно &quot;Дополнительные параметры сохранения&quot; в Visual Studio

    Если вы не сохраните исходный код в кодировке UTF8, Visual Studio может сохранить его как файл ASCII.If you fail to save your source code as a UTF8-encoded file, Visual Studio may save it as an ASCII file. В этом случае среде выполнения не удастся правильно раскодировать символы UTF8 за пределами стандартного диапазона ASCII, и результаты теста будут неправильными.When that happens, the runtime doesn't accurately decode the UTF8 characters outside of the ASCII range, and the test results won't be correct.

  5. В строке меню выберите Тест > Выполнить все тесты.On the menu bar, select Test > Run All Tests. Если окно обозревателя тестов не открыто, откройте его, выбрав Тест > Обозреватель тестов.If the Test Explorer window doesn't open, open it by choosing Test > Test Explorer. В разделе Пройденные тесты перечислены три теста, а раздел Сводка содержит результат тестового запуска.The three tests are listed in the Passed Tests section, and the Summary section reports the result of the test run.

    Окно &quot;Обозреватель тестов&quot; с пройденными тестами

Обработка сбоев тестаHandle test failures

Выполняя разработку на основе тестирования (TDD), вы сначала пишете тесты, и они завершаются сбоем при первом запуске.If you're doing test-driven development (TDD), you write tests first and they fail the first time you run them. Затем вы добавляете код в приложение, и тест успешно выполняется.Then you add code to the app that makes the test succeed. В рамках этого учебника вы создали тест после написания кода приложения для его проверки, поэтому тест был пройден.For this tutorial, you created the test after writing the app code that it validates, so you haven't seen the test fail. Чтобы проверить, завершается ли тест ошибкой, как и ожидается, добавьте недопустимое значение во входные данные теста.To validate that a test fails when you expect it to fail, add an invalid value to the test input.

  1. Измените массив words в методе TestDoesNotStartWithUpper, включив в него строку "Error".Modify the words array in the TestDoesNotStartWithUpper method to include the string "Error". Сохранять файл не требуется, поскольку при сборке решения для выполнения тестов Visual Studio автоматически сохраняет открытые файлы.You don't need to save the file because Visual Studio automatically saves open files when a solution is built to run tests.

    string[] words = { "alphabet", "Error", "zebra", "abc", "αυτοκινητοβιομηχανία", "государство",
                       "1234", ".", ";", " " };
    
    Dim words() As String = { "alphabet", "Error", "zebra", "abc", "αυτοκινητοβιομηχανία", "государство",
                       "1234", ".", ";", " " }
    
    
  2. Выполните тест, последовательно выбрав в строке меню пункты Тест > Выполнить все тесты.Run the test by selecting Test > Run All Tests from the menu bar. В окне Обозреватель тестов будет указано, что два теста выполнены успешно, а третий завершился ошибкой.The Test Explorer window indicates that two tests succeeded and one failed.

    Окно Обозреватель тестов с тестами, которые завершились ошибкой

  3. Выберите непройденный тест TestDoesNotStartWith.Select the failed test, TestDoesNotStartWith.

    В окне Обозреватель тестов появится сообщение, созданное методом утверждения "Assert.IsFalse failed.The Test Explorer window displays the message produced by the assert: "Assert.IsFalse failed. Expected for 'Error': false; actual: True".Expected for 'Error': false; actual: True". Из-за этого сбоя строки в массиве, расположенные после слова "Error", не проверялись.Because of the failure, no strings in the array after "Error" were tested.

    Окно Обозреватель тестов с сообщением о том, что утверждение IsFalse ошибочно

  4. Удалите строку "Error", которую вы добавили на шаге 1.Remove the string "Error" that you added in step 1. Еще раз запустите тест. Теперь тесты будут пройдены.Rerun the test and the tests pass.

Тестирование версии выпуска для библиотекиTest the Release version of the library

Теперь, когда все тесты пройдены при выполнении сборки в режиме отладки, следует запустить все тесты еще раз, теперь уже для сборки библиотеки в режиме выпуска.Now that the tests have all passed when running the Debug build of the library, run the tests an additional time against the Release build of the library. Некоторые факторы, например оптимизации компилятора, иногда могут вызывать разное поведение сборки в режимах отладки и выпуска.A number of factors, including compiler optimizations, can sometimes produce different behavior between Debug and Release builds.

Протестируйте сборку выпуска следующим образом.To test the Release build:

  1. В панели инструментов Visual Studio измените конфигурацию сборки с режима Отладка на Выпуск.In the Visual Studio toolbar, change the build configuration from Debug to Release.

    Панель инструментов Visual Studio с выделенной сборкой выпуска

  2. В обозревателе решений щелкните проект StringLibrary правой кнопкой мыши и выберите в контекстном меню пункт Сборка, чтобы выполнить повторную компиляцию библиотеки.In Solution Explorer, right-click the StringLibrary project and select Build from the context menu to recompile the library.

    Контекстное меню проекта StringLibrary с командой сборки

  3. Выполните модульные тесты, выбрав в строке меню Тест > Выполнить все тесты.Run the unit tests by choosing Test Run > All Tests from the menu bar. Все тесты будут пройдены.The tests pass.

Отладка тестовDebug tests

Если в качестве IDE вы используете Visual Studio, то можете следовать инструкциям из руководства по отладке консольного приложения .NET с помощью Visual Studio, чтобы выполнить отладку кода с применением проекта модульного теста.If you're using Visual Studio as your IDE, you can use the same process shown in Tutorial: Debug a .NET console application using Visual Studio to debug code using your unit test project. Вместо запуска проекта приложения ShowCase щелкните правой кнопкой проект StringLibraryTests и выберите элемент Отладка тестов в контекстном меню.Instead of starting the ShowCase app project, right-click the StringLibraryTests project, and select Debug Tests from the context menu.

Visual Studio запускает тестовый проект с присоединенным отладчиком.Visual Studio starts the test project with the debugger attached. Выполнение будет прервано в любой точке останова, добавленной в тестовый проект или базовый код библиотеки.Execution will stop at any breakpoint you've added to the test project or the underlying library code.

Дополнительные ресурсыAdditional resources

Следующие шагиNext steps

В этом руководстве вы выполнили модульное тестирование библиотеки классов.In this tutorial, you unit tested a class library. Чтобы сделать библиотеку доступной другим пользователям, опубликуйте ее в NuGet в качестве пакета.You can make the library available to others by publishing it to NuGet as a package. Чтобы узнать, как это делать, следуйте указаниям в руководстве по NuGet:To learn how, follow a NuGet tutorial:

Если библиотека опубликована как пакет NuGet, ее могут устанавливать и использовать другие пользователи.If you publish a library as a NuGet package, others can install and use it. Чтобы узнать, как это делать, следуйте указаниям в руководстве по NuGet:To learn how, follow a NuGet tutorial:

Библиотеку не нужно распространять как пакет.A library doesn't have to be distributed as a package. Ее можно объединить с консольным приложением, где она используется.It can be bundled with a console app that uses it. Чтобы узнать, как опубликовать консольное приложение, ознакомьтесь с предыдущим руководством в этой серии:To learn how to publish a console app, see the earlier tutorial in this series: