Anatomy of a Unit Test

When you create a unit test, several files are added to your solution. In this topic, we will use an example of a unit test to explore the most common files. The example comes from the topic Walkthrough: Creating and Running Unit Tests.

Parts of a unit test file

When you create a unit test, a separate unit test file is created for each class that you are testing. Each unit test file contains a test method for each method that you are testing. In this example, both the methods we are testing belong to the same class. Therefore, there is only one test-class file: BankAccountTest.cs.

Top section of the file

The following figure shows the first few lines of code, including the reference to the namespaces, the TestClassAttribute, and the TestContext class. See the walkthrough if you want code samples.

Top section of a sample unit test file

  1. Microsoft.VisualStudio.TestTools.UnitTesting: When you create a unit test, a reference to the Microsoft.VisualStudio.TestTools.UnitTesting namespace is added to your test project and the namespace is included in a using statement at the top of the unit test file. The namespace has many classes to help you with your unit tests including:

    • Assert classes that you can use to verify conditions in unit tests

    • Initialization and cleanup attributes to run code before or after unit tests run to ensure a specific beginning and ending state

    • The ExpectedException attribute to verify that a certain type of exception is thrown during unit test execution

    • The TestContext class which stores information that is provided to unit tests such as data connection for data-driven tests and information that is required to run unit tests for ASP.NET Web Services

    For more information, see Microsoft.VisualStudio.TestTools.UnitTesting.

  2. TestClassAttribute: When you create a unit test the TestClassAttribute is included in the test file to indicate that this particular class may contain methods marked with the [TestMethod()] attribute. Without the TestClassAttribute, the test methods are ignored.

    A test class can inherit methods from another test class that is in the same assembly. This means that you can create test methods in a base test class and then use those methods in derived test classes.

    For more information, see TestClassAttribute.

  3. TestContext: When you create unit tests, a variable called testContextInstance is included for each test class. The properties of the TestContext class store information about the current test. For more information, see TestContext.

Bottom section of the file

The following figure shows the latter part of the code that is generated in the walkthrough, which includes the "Additional test attributes" section, the TestMethod attribute, and the logic of the method, which includes an Assert statement.

Bottom section of a sample unit test file

  1. Additional test attributes: Expand this section to show commented-out methods that can be used to include initialization and cleanup by using the following attributes:

    1. [ClassInitialize()]   Use ClassInitialize to run code before you run the first test in the class.

    2. [ClassCleanUp()]   Use ClassCleanup to run code after all tests in a class have run.

    3. [TestInitialize()]   Use TestInitialize to run code before you run each test.

    4. [TestCleanUp()]   Use TestCleanup to run code after each test has run.

      Create methods that are marked with either the [ClassInitialize()] or [TestInitialize()] attribute to prepare aspects of the environment in which your unit test will run. The purpose of this is to establish a known state for running your unit test. For example, you may use the [ClassInitialize()] or the [TestInitialize()] method to copy, alter, or create certain data files that your test will use.

      Create methods that are marked with either the [ClassCleanup()] or [TestCleanUp{}] attribute to return the environment to a known state after a test has run. This might mean the deletion of files in folders or the return of a database to a known state. An example of this is to reset an inventory database to an initial state after testing a method that is used in an order-entry application.

      Note

      It is recommended that you use cleanup code in a [TestCleanup()] or [ClassCleanup()] method and not in a finalizer method. Exceptions that are thrown from a finalizer method will not be caught and can cause unexpected results.

  2. TestMethodAttribute: When you create a unit test, each unit test method is marked with the [TestMethod()] attribute. Without this attribute a unit test does not run. For more information about the TestMethod attribute see TestMethodAttribute.

  3. Logic of the test method, including an Assert statement: Each unit test that is generated has empty variables and a placeholder Assert statement. The default placeholder Assert statement is usually the Assert.Inconclusive statement. To make the test meaningful, you must initialize the variables and replace the placeholder with an appropriate Assert statement.

    In this example we left the CreditTest unit test method as it was generated, including its TODO statements. However, we initialized the variables and replaced the Assert statement in the DebitTest test method. TODO statements act as reminders that you might want to initialize these lines of code.

    Note

    The contents of your test methods might vary, depending on the type of unit test and the nature of the method being tested.

A note about naming conventions: The Visual Studio testing tools use naming conventions when unit tests are generated. For example, a unit test file is named by concatenating the word "Test" with the name of the file that contains the code that you are testing; in our example it is "BankAccountTest.cs." Names of test classes and test methods are generated by using defaults also. You can change these defaults in the Test Generation Settings dialog box, which you can open by clicking Settings on the Create Unit Tests dialog box.

Items added to the solution

This section covers the files other than the unit test file that are generated in Walkthrough: Creating and Running Unit Tests.

Note

Which files are created by default when you generate a unit test depends on the test project settings. To change these settings, click Tools, and then click Options. In the Options dialog box, expand Test Tools and then click Test Project.

The following figure shows Solution Explorer after a unit test was created for our example project.

Solution Explorer for a sample unit test project

  1. Solution Items: Solution Items contains two files:

    • Local.testsettings: These settings control how local tests that do not collect diagnostic data are run.

    • Bank.vsmdi: This file contains information about test lists that are present in the solution and populates the Test List Editor window.

    • TraceAndTestImpact.testsettings: These settings control how local tests that collect a specific set of diagnostic data are run.

  2. Test Project: Contains the remaining files that are required for the unit tests.

  3. Test Project Properties: Contains the AssemblyInfo.cs file, which provides build options for the project.

  4. Test Project References: Contains references that are required to run your unit tests. When you generate a unit test from existing code, the required references are included. However, you can add references to customize your tests.

  5. Unit test file: This is the unit test file described in the first section of this topic. For each class that you are testing, a separate unit test file is created in the test project. In this example, both of the methods we are testing belong to the same class. Therefore, there is only one test class file, BankAccountTest.cs.

See Also

Reference

Microsoft.VisualStudio.TestTools.UnitTesting

Concepts

Creating and Running Unit Tests for Existing Code

Unit Tests and C++

Unit Tests For Generic Methods

Unit Tests for ASP.NET Web Services

Unit Tests for Private, Internal, and Friend Methods