Test a .NET Standard library with .NET Core in Visual Studio 2017

In Build a .NET Standard library with C# and .NET Core in Visual Studio 2017 or Build a .NET Standard library with Visual Basic and .NET Core in Visual Studio 2017, you created a simple class library that adds an extension method to the String class. Now, you'll create a unit test to make sure that it works as expected. You'll add your unit test project to the solution you created in the previous article.

Creating a unit test project

To create the unit test project, do the following:

  1. In Solution Explorer, open the context menu for the ClassLibraryProjects solution node and select Add > New Project.

  2. In the Add New Project dialog, select the Visual C# node. Then select the .NET Core node followed by the MSTest Test Project (.NET Core) project template. In the Name text box, enter "StringLibraryTest" as the name of the project. Select OK to create the unit test project.

    Add New Project dialog with unit test project displayed - C#

    Note

    In addition to an MSTest Test project, you can also use Visual Studio to create an xUnit test project for .NET Core.

  3. Visual Studio creates the project and opens the UnitTest1.cs file in the code window.

    Visual Studio code window for the unit test project class and method - C#

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

    • It imports the Microsoft.VisualStudio.TestTools.UnitTesting namespace, which contains the types used for unit testing.

    • It applies the TestClassAttribute attribute to the UnitTest1 class. Each test method in a test class tagged with the [TestMethod] attribute is executed automatically when the unit test is run.

    • It applies the TestMethodAttribute attribute to define TestMethod1 as a test method for automatic execution when the unit test is run.

  4. In Solution Explorer, right-click the Dependencies node of the StringLibraryTest project and select Add Reference from the context menu.

    Context menu of StringLibraryTest Dependencies - C#

  5. In the Reference Manager dialog, expand the Projects node and check the box next to StringLibrary. Adding a reference to the StringLibrary assembly allows the compiler to find StringLibrary methods. Select the OK button. This adds a reference to your class library project, StringLibrary.

    Visual Studio add project reference dialog

Adding and running unit test methods

When Visual Studio runs a unit test, it executes each method marked with the TestMethodAttribute attribute in a unit test class, the class to which the TestClassAttribute attribute is applied. A test method ends when the first failure is encountered 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 its most frequently called methods are shown in the table below.

Assert methods Function
Assert.AreEqual Verifies that two values or objects are equal. The assert fails if the values or objects are not 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 is not null. The assert fails if the object is null.

You can also apply the ExpectedExceptionAttribute attribute to a test method. It indicates the type of exception a test method is expected to throw. The test fails if the specified exception is not 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 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 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 has not been initialized. If StartsWithUpper is called as an extension method on a String instance, it cannot be passed a null string. However, you can also call it directly as a static method and pass a single String argument.

You'll define three methods, each of which calls its Assert method repeatedly for each element in a string array. Because the test method fails as soon as it encounters the first failure, you'll call a method overload that allows you to pass a string that indicates the string value used in the method call.

To create the test methods:

  1. In the UnitTest1.cs 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));
                }
            }
        }
    }
    

    Note that your test of uppercase characters in the TestStartsWithUpper method includes the Greek capital letter alpha (U+0391) and the Cyrillic capital letter EM (U+041C), and 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 UnitTest1.cs As. In the Save File As dialog, select the arrow beside the Save button, and select Save with Encoding.

    Visual Studio Save File As dialog - C#

  1. In the Confirm Save As dialog, select the Yes button to save the file.

  2. In the Advanced Save Options dialog, select Unicode (UTF-8 with signature) - Codepage 65001 from the Encoding drop-down list and select OK.

    Visual Studio Advanced Save Options dialog

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

  3. On the menu bar, select Test > Run > All Tests. The Test Explorer window opens and shows that the tests ran successfully. The three tests are listed in the Passed Tests section, and the Summary section reports the result of the test run.

    Test Explorer window with passing tests

Handling test failures

Your test run had no failures, but change it slightly so that one of the test methods fails:

  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", ".", ";", " " };
    
    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.

    Test Explorer window with failing tests

  3. In the Failed Tests section, select the failed test, TestDoesNotStartWith. The Test Explorer window displays the message produced by the assert: "Assert.IsFalse failed. Expected for 'Error': false; actual: True". Because of the failure, all strings in the array after "Error" were not tested.

    Test Explorer window showing the Is False assertion failure

  4. Undo the modification you did in step 1 and remove the string "Error". Rerun the test and the tests will pass.

Testing the Release version of the library

You've been running your tests against the Debug version of the library. Now that your tests have all passed and you've adequately tested your library, you should 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 Solution Explorer, right-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 by choosing Test > Run > All Tests from the menu bar. The tests pass.

Now that you've finished testing your library, the next step is to make it available to callers. You can bundle it with one or more applications, or you can distribute it as a NuGet package. For more information, see Consuming a .NET Standard Class Library.