Get started with Live Unit Testing

When you enable Live Unit Testing in a Visual Studio solution, it visually depicts your test coverage and the status of your tests. Live Unit Testing also dynamically executes tests whenever you modify your code and immediately notifies you when your changes cause tests to fail.

Live Unit Testing can be used to test solutions that target either .NET Framework or .NET Core. In this tutorial, you'll learn to use Live Unit Testing by creating a simple class library that targets .NET Standard, and you'll create an MSTest project that targets .NET Core to test it.

The complete C# solution can be downloaded from the MicrosoftDocs/visualstudio-docs repo on GitHub.

Prerequisites

This tutorial requires that you've installed Visual Studio Enterprise edition with the .NET Core cross-platform development workload.

Create the solution and the class library project

Begin by creating a Visual Studio solution named UtilityLibraries that consists of a single .NET Standard class library project, StringLibrary.

The solution is just a container for one or more projects. To create a blank solution, open Visual Studio and do the following:

  1. Select File > New > Project from the top-level Visual Studio menu.

  2. Type solution into the template search box, and then select the Blank Solution template.

    The New Project dialog

  3. Finish creating the solution.

Now that you've created the solution, you'll create a class library named StringLibrary that contains a number of extension methods for working with strings.

  1. In Solution Explorer, right-click on the UtilityLibraries solution and select Add > New Project.
  1. In the Add New Project dialog, select the C# node, then select .NET Standard.

    Note

    Because our library targets .NET Standard rather than a particular .NET implementation, it can be called from any .NET implementation that supports that version of .NET Standard. For more information, see .NET Standard.

  2. Select the Class Library (.NET Standard) template in the right pane, and enter StringLibrary in the Name text box, as the following image shows:

    The Add New Project dialog

  3. Select OK to create the project.

  1. Type class library into the template search box, and the select the Class Library (.NET Standard) template. Click Next.

    Note

    Because our library targets .NET Standard rather than a particular .NET implementation, it can be called from any .NET implementation that supports that version of .NET Standard. For more information, see .NET Standard.

  2. Name the project StringLibrary.

  3. Click Create to create the project.

  1. Replace all of the existing code in the code window with the following code:

    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 has three static methods:

    • StartsWithUpper returns true if a string starts with an uppercase character; otherwise, it returns false.

    • StartsWithLowerreturns true if a string starts with a lowercase character; otherwise, it returns false.

    • HasEmbeddedSpaces returns true if a string contains an embedded whitespace character; otherwise, it returns false.

  2. Select Build > Build Solution from the top-level Visual Studio menu. The build should succeed.

Create the test project

The next step is to create the unit test project to test the StringLibrary library. Create the unit tests by performing the following steps:

  1. In Solution Explorer, right-click on the UtilityLibraries solution and select Add > New Project.
  1. In the Add New Project dialog, select the C# node, then select .NET Core.

    Note

    You do not have to write your unit tests in the same language as your class library.

  2. Select the Unit Test Project (.NET Core) template in the right pane, and enter StringLibraryTests in the Name text box, as the following image shows:

    The Add New Project dialog for the unit test project

  3. Select OK to create the project.

  1. Type unit test into the template search box, and the select the Unit Test Project (.NET Core) template. Click Next.

  2. Name the project StringLibraryTests.

  3. Click Create to create the project.

Note

This getting started tutorial uses Live Unit Testing with the MSTest test framework. You can also use the xUnit and NUnit test frameworks.

  1. The unit test project can't automatically access the class library that it is testing. You give the test library access by adding a reference to the class library project. To do this, right-click on the StringLibraryTests project and select Add > Reference. In the Reference Manager dialog, make sure the Solution tab is selected, and select the StringLibrary project, as shown in the following image.

    The Reference Manager dialog

  2. Replace the boilerplate unit test code provided by the template 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,
                                  $"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}");
                }
            }
        }
    }
    
  3. Save your project by selecting the Save icon on the toolbar.

  4. Because the unit test code includes some non-ASCII characters, Visual Studio displays the following dialog to warn that some characters will be lost if you save the file in its default ASCII format. Choose the Save with Other Encoding button.

    Choose a file encoding

  5. In the Encoding drop-down list of the Advance Save Options dialog, choose Unicode (UTF-8 without signature) - Codepage 65001, as the following image shows:

    Choosing the UTF-8 encoding

  6. Compile the unit test project by selecting Build > Rebuild Solution from the top-level Visual Studio menu.

You've created a class library as well as some unit tests for it. You've now finished the preliminaries needed to use Live Unit Testing.

Enable Live Unit Testing

So far, although you've written the tests for the StringLibrary class library, you haven't executed them. Live Unit Testing executes them automatically once you enable it. To do that, do the following:

  1. Optionally, select the code window that contains the code for StringLibrary. This is either Class1.cs for a C# project or Class1.vb for a Visual Basic project. (This step lets you visually inspect the result of your tests and the extent of your code coverage once you enable Live Unit Testing.)

  2. Select Test > Live Unit Testing > Start from the top-level Visual Studio menu.

  3. Visual Studio starts Live Unit Test, which automatically runs all of your tests.

When it finishes running your tests, Test Explorer displays both the overall results and the result of individual tests. In addition, the code window graphically displays both your test code coverage and the result for your tests. As the following image shows, all three tests have executed successfully. It also shows that our tests have covered all code paths in the StartsWithUpper method, and those tests all executed successfully (which is indicated by the green check mark, "✓"). Finally, it shows that none of the other methods in StringLibrary have code coverage (which is indicated by a blue line, "➖").

The Test Explorer and code window after starting Live Unit testing

You can also get more detailed information about test coverage and test results by selecting a particular code coverage icon in the code window. To examine this detail, do the following:

  1. Click on the green check mark on the line that reads if (String.IsNullOrWhiteSpace(s)) in the StartsWithUpper method. As the following image shows, Live Unit Testing indicates that three tests cover that line of code, and that all have executed successfully.

    Code coverage for the if conditional statement

  2. Click on the green check mark on the line that reads return Char.IsUpper(s[0]) in the StartsWithUpper method. As the following image shows, Live Unit Testing indicates that only two tests cover that line of code, and that all have executed successfully.

    Code coverage for the return statement

The major issue that Live Unit Testing identifies is incomplete code coverage. You'll address it in the next section.

Expand test coverage

In this section, you'll extend your unit tests to the StartsWithLower method. While you do that, Live Unit Testing will dynamically continue to test your code.

To extend code coverage to the StartsWithLower method, do the following:

  1. Add the following TestStartsWithLower and TestDoesNotStartWithLower methods to your project's test source code file:

    // 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. Modify the DirectCallWithNullOrEmpty method by adding the following code immediately after the call to the Microsoft.VisualStudio.TestTools.UnitTesting.Assert.IsFalse method.

    // 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 automatically executes new and modified tests when you modify your source code. As the following image of Test Explorer shows, all of the tests, including the two you've added and the one you've modified, have succeeded.

    The Test Explorer after expanding test coverage

  4. Switch to the window that contains the source code for the StringLibrary class. Live Unit Testing now shows that our code coverage is extended to the StartsWithLower method.

    Code coverage for the StartsWithLower method

In some cases, successful tests in Test Explorer may be grayed-out. That indicates that a test is currently executing, or that the test has not run again because there have been no code changes that would impact the test since it was last executed.

So far, all of our tests have succeeded. In the next section, we'll examine how you can handle test failure.

Handle a test failure

In this section, you'll explore how you can use Live Unit Testing to identify, troubleshoot, and address test failures. You'll do this by expanding test coverage to the HasEmbeddedSpaces method.

  1. Add the following method to your test file:

    [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. When the test executes, Live Unit Testing indicates that the TestHasEmbeddedSpaces method has failed, as the following image shows:

    The Test Explorer reporting a failed test

  3. Select the window that displays the library code. Live Unit Testing has expanded code coverage to the HasEmbeddedSpaces method. It also reports the test failure by adding a red "🞩" to lines covered by failing tests.

  4. Hover over the line with the HasEmbeddedSpaces method signature. Live Unit Testing displays a tooltip that reports that the method is covered by one test, as the following image shows:

    Live Unit Testing information on a failed test

  5. Select the failed TestHasEmbeddedSpaces test. Live Unit Testing gives you a number of options, such as running all tests, running the selected tests, debugging all tests, and debugging selected tests, as the following image shows:

    Live Unit Testing options for a failed test

  6. Select Debug Selected to debug the failed test.

  7. Visual Studio executes the test in debug mode.

    The test assigns each string in an array to a variable named phrase and passes it to the HasEmbeddedSpaces method. Program execution pauses and invokes the debugger the first time the assert expression is false. The exception dialog that results from the unexpected value in the Microsoft.VisualStudio.TestTools.UnitTesting.Assert.IsTrue method call is shown in the following image.

    Live Unit Testing exception dialog

    In addition, all of the debugging tools that Visual Studio provides are available to help us troubleshoot our failed test, as the following image shows:

    Visual Studio debugging tools

    Note in the Autos window that the value of the phrase variable is "Name\tDescription", which is the second element of the array. The test method expects HasEmbeddedSpaces to return true when it is passed this string; instead, it returns false. Evidently, it does not recognize "\t", the tab character, as an embedded space.

  8. Select Debug > Continue, press F5, or click the Continue button on the toolbar to continue executing the test program. Because an unhandled exception occurred, the test terminates. This provides enough information for a preliminary investigation of the bug. Either TestHasEmbeddedSpaces (the test routine) made an incorrect assumption, or HasEmbeddedSpaces does not correctly recognize all embedded spaces.

  9. To diagnose and correct the problem, start with the StringLibrary.HasEmbeddedSpaces method. Look at the comparison in the HasEmbeddedSpaces method. It considers an embedded space to be U+0020. However, the Unicode Standard includes a number of other space characters. This suggests that the library code has incorrectly tested for a whitespace character.

  10. Replace the equality comparison with a call to the System.Char.IsWhiteSpace method:

    if (Char.IsWhiteSpace(ch))
    
  11. Live Unit Testing automatically reruns the failed test method and updates the results in the code window and in Test Explorer, as the following image shows:

    Successful HasEmbeddedSpaces test

See also