Test a .NET class library using Visual Studio

Important

Microsoft has announced the retirement of Visual Studio for Mac. Visual Studio for Mac will no longer be supported starting August 31, 2024. Alternatives include:

  • Visual Studio Code with the C# Dev Kit and related extensions, such as .NET MAUI and Unity.
  • Visual Studio running on Windows in a VM on Mac.
  • Visual Studio running on Windows in a VM in the Cloud.

For more information, see Visual Studio for Mac retirement announcement.

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 is one of three test frameworks you can choose from. The others are xUnit and nUnit.

  1. Start Visual Studio for Mac.

  2. Open the ClassLibraryProjects solution you created in Create a .NET class library using Visual Studio for Mac.

  3. In the Solution pad, ctrl-click the ClassLibraryProjects solution and select Add > New Project.

  4. In the New Project dialog, select Tests from the Web and Console node. Select the MSTest Project followed by Next.

    Visual Studio Mac New Project dialog creating test project

  5. Select .NET 5.0 as the Target Framework and select Next.

  6. Name the new project "StringLibraryTest" and select Create.

    Visual Studio Mac New Project dialog providing project name

    Visual Studio creates a class file with the following code:

    using Microsoft.VisualStudio.TestTools.UnitTesting;
    
    namespace StringLibraryTest
    {
        [TestClass]
        public class UnitTest1
        {
            [TestMethod]
            public void TestMethod1()
            {
            }
        }
    }
    

    The source code created by the unit test template does the following:

    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

For the test project to work with the StringLibrary class, add a reference to the StringLibrary project.

  1. In the Solution pad, ctrl-click Dependencies under StringLibraryTest. Select Add Reference from the context menu.

  2. In the References dialog, select the StringLibrary project. Select OK.

    Visual Studio Mac Edit References dialog

Add and run unit test methods

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.

The most common tests call members of the Assert class. 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. 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 Verifies that a condition is false. The assert fails if the condition is true.
Assert.IsNotNull Verifies that an object isn't null. The assert fails if the object is null.

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.

In testing the StringLibrary.StartsWithUpper method, you want to provide a number of strings that begin with an uppercase character. 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. You expect the method to return false in these cases, so you can call the Assert.IsFalse method.

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. You can call StartsWithUpper directly as a static method and pass a single String argument. Or you can call StartsWithUpper as an extension method on a string variable assigned to null.

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. Open the UnitTest1.cs file and replace the code with the following code:

    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));
                }
            }
        }
    }
    

    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). 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. On the menu bar, select File > Save As. In the dialog, make sure that Encoding is set to Unicode (UTF-8).

    Visual Studio Save File As dialog

  3. When you're asked if you want to replace the existing file, select Replace.

    If you fail to save your source code as a UTF8-encoded file, Visual Studio may save it as an ASCII file. 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.

  4. Open the Unit Tests panel on the right side of the screen. Select View > Tests from the menu.

  5. Click the Dock icon to keep the panel open.

    Visual Studio for Mac Unit Tests panel dock icon

  6. Click the Run All button.

    All tests pass.

    Visual Studio for Mac expected test passes

Handle test failures

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. Modify the words array in the TestDoesNotStartWithUpper method to include the string "Error". 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", ".", ";", " " };
    
  2. Run the tests again.

    This time, the Test Explorer window indicates that two tests succeeded and one failed.

    Test Explorer window with failing tests

  3. ctrl-click the failed test, TestDoesNotStartWithUpper, and select Show Results Pad from the context menu.

    The Results pad displays the message produced by the assert: "Assert.IsFalse failed. Expected for 'Error': false; actual: True". Because of the failure, no strings in the array after "Error" were tested.

    Test Explorer window showing the IsFalse assertion failure

  4. 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. In the Visual Studio toolbar, change the build configuration from Debug to Release.

    Visual Studio toolbar with release build highlighted

  2. In the Solution pad, ctrl-click the StringLibrary project and select Build from the context menu to recompile the library.

    StringLibrary context menu with build command

  3. Run the unit tests again.

    The tests pass.

Debug tests

If you're using Visual Studio for Mac as your IDE, you can use the same process shown in Tutorial: Debug a .NET console application using Visual Studio for Mac to debug code using your unit test project. Instead of starting the ShowCase app project, ctrl-click the StringLibraryTests project, and select Start Debugging Project from the context menu.

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. You can make the library available to others by publishing it to NuGet as a package. To learn how, follow a NuGet tutorial:

If you publish a library as a NuGet package, others can install and use it. 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: