Structure of Unit Tests

A unit test is a method that is a member of a class written in C#, Visual Basic, or Visual C++.

Note

For details on how to use unit tests with C++ production code and how to use unit tests written in C++, see Unit Tests and C++.

For the unit test to be recognized by the Team System testing tools, this source-code file must reside in a test project, which in turn is a part of a Visual Studio solution. When you build this project, or the entire solution, the test project is built into an assembly that contains the executable unit test.

All unit test methods are marked with the [TestMethod()] attribute, <TestMethod()> in Visual Basic, and are members of the [TestClass()] class. In turn, this class is defined in the namespace Microsoft.VisualStudio.TestTools.UnitTesting. When you generate a unit test, you see that this namespace is included at the beginning of the generated file, in a using or Imports statement.

Unit Test Attributes and Properties

In addition to the [TestMethod()] attribute of the unit test method and the [TestClass()] attribute of its containing class, other attributes are used to enable specific unit-test functionality. Primary among these attributes are [TestInitialize()] and [TestCleanup()]. Use a method marked with [TestInitialize()] to prepare aspects of the environment in which your unit test will run; the purpose of doing this is to establish a known state for running your unit test. For example, you may use a [TestInitialize()] method to copy, alter, or create certain data files that your test will use.

Use a method marked with [TestCleanup()] to return the environment to a known state after a test has run; this might mean deleting files in folders, or returning a database to a known state. An example of this is resetting an inventory database to an initial state after testing a method used in an order-entry application. Furthermore, 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.

An important property on test classes is the TestContext property. This property contains information including the name of the unit test that is currently running, the deployment directory, the names of log files, and for data-driven testing, the database to which you are connected. The TestContext property returns a TestContext instance. For more information, see Using the TestContext Class.

Unit Test Example

The following code snippet shows a simple unit test written in C#.

[TestMethod()]
public void DebitTest()
{
    string customerName = "Mr. Bryan Walton"; 
    double balance = 11.99; 
    BankAccount target = new BankAccount(customerName, balance);
    double amount = 11.22; 
    target.Debit(amount);
    Assert.AreEqual((System.Convert.ToDouble(0.77)), target.Balance, 0.05); // 0.05 is tolerance for floating-point comparison
    //Assert.Inconclusive("A method that does not return a value cannot be verified.");
}

For another example, see Coding a Data-Driven Unit Test.

Unit Test Outcomes

There are three ways to verify that a unit test has passed:

  • Use one or more Assert statements to validate specific outcomes. For more information, see Using Assert Statements.

  • Verify that no exception was thrown. It is still advisable to use one or more Assert statements.

  • Verify that a particular exception is thrown. You can do this by using the ExpectedExceptionAttribute attribute.

Using Assert Statements

If the Pass or Fail result that a test produces is more informative or important to you than the actions that the test might complete, you should use one or more Assert statements in the test's code.

The test engine assumes that every unit test starts in a passing state. The test remains in that state until an Assert statement produces a result that contradicts the passing state, changing it from Pass to Fail or Inconclusive, or until an exception not specified in an ExpectedExceptionAttribute attribute is thrown. In another words, a unit test without an Assert statement will produce a Pass result every time it is run. This is not necessarily a useless test; you might just want to exercise the code to make sure it runs without throwing an exception. Code exercised in a unit test will be reported as covered in the code-coverage statistics regardless of whether the test produced a decisive result or even contained an Assert statement.

However, to verify that a specific action is being taken or a specific state is being reached, you must use Asserts. Several Assert statements are available to you in the Microsoft.VisualStudio.TestTools.UnitTesting namespace. The various Assert statements give you flexibility; for example, you can force a test to fail by using the statement Assert.Fail(). In addition to these Assert statements, you can, of course, construct your own custom functionality, perhaps by using Assert statements in if blocks.

Regardless of what results a test returns, it passes or fails depending on its Assert statements. If a test contains several Asserts, the state of the test remains Pass until an Assert is encountered that changes the state to Fail or Inconclusive.

For more information, see Using the Assert Classes.

See Also

Reference

Microsoft.VisualStudio.TestTools.UnitTesting

Other Resources

Creating Unit Tests