Free Trial

Safari Books Online is a digital library providing on-demand subscription access to thousands of learning resources.

Share this Page URL

Chapter 22. Unit Testing > Metadata and Assertions

Feedback: 0 Comments on this Section

Metadata and Assertions

Metadata and Assertions As you have seen, attributes are used to identify test classes and methods. Attributes can also be used to provide other metadata information to the UTF. This section examines each of the UTF attributes in greater detail and provides descriptions of their usage, purpose, and effect on test execution. TestClass Attribute The TestClass attribute indicates that a class contains test methods. TestMethod Attribute The TestMethod attribute indicates that a method should be included in the suite of tests. The Ignore attribute can be used to temporarily exclude a test method from the suite of tests. Methods decorated with the TestMethod attribute should be public and have a void return type. Metadata for Test Initialization and Cleanup The UTF provides attributes that allow you to specify methods that should be run before and after test execution. You can provide methods that are executed once for each test assembly, once for each test class, and once for each test method. The order in which methods decorated with each particular attribute are run is presented in Figure 22.5. Figure 22.5. Test execution order is affected by initialization and cleanup metadata. AssemblyInitialize Attribute The AssemblyInitialize attribute identifies a method that contains code to be used before all tests in an assembly are run and to allocate resources obtained by the assembly. A method decorated with the AssemblyInitialize attribute must be public and static, and have a void return type. The following demonstrates the use of the AssemblyInitialize attribute: [AssemblyInitialize]
public static void AssemblyInitialize()
    /* Assembly initialization logic goes here. */
} Note The test framework runs a method that is marked with the AssemblyInitialize attribute only if that method is a member of a class that is marked with the TestClass attribute. AssemblyCleanup Attribute The AssemblyCleanup attribute is analogous to the AssemblyInitialize attribute but occurs at the end of the test run. As with the AssemblyInitialize attribute, a method decorated with this attribute should be located in a test class. The following shows an example of a method decorated with the AssemblyCleanup attribute: [AssemblyCleanup]
public static void AssemblyCleanup()
    /* Assembly cleanup logic goes here. */
} ClassInitialize Attribute The ClassInitialize attribute provides the opportunity to run code before any of the tests in the test class have run and to allocate resources to be used by the test class. A method decorated with the ClassInitialize attribute must be public and static with a void return type. Only one method in a class may be decorated with this attribute. The following shows an example of a method decorated with the ClassInitialize attribute: [ClassInitialize]
public static void ClassInitialize()
    /* Class initialization logic goes here. */
} ClassCleanup Attribute The ClassCleanup attribute is analogous to the ClassInitialize attribute but occurs after all test methods have completed within the test class. The following shows an example of a method decorated with the ClassCleanup attribute: [ClassCleanup]
public static void ClassCleanup()
    /* Class cleanup logic goes here. */
} TestInitialize Attribute The TestInitialize attribute is used to indicate that a method decorated with this attribute should be called before every test method within a test class. A method decorated with the TestInitialize attribute must be public and have a void return type. The following shows an example of a method decorated with the TestInitialize attribute: [TestInitialize]
public void TestInitialize()
    /* Test initialization logic goes here. */
} Tip If more than one method is decorated with the TestInitialize attribute in a test class, it prevents the execution of all test methods. Furthermore, it does so silently. If you find that the debugger is failing to hit a break point in a test method, look for a duplication of the TestInitialize attribute. TestCleanup Attribute The TestCleanup attribute is useful for resetting the state of shared resources in between test methods, such as an object that is used by all tests within a test class. [TestCleanup]
public void TestCleanup()
    /* Test cleanup logic goes here. */
} Miscellaneous Metadata The following attributes allow you to control various other aspects of test execution. TestProperty Attribute The TestProperty attribute allows arbitrary metadata to be associated with a test method. For example, you could use it to store the name of a test pass that this test covers by decorating the test method with [TestProperty("TestPass", "Accessibility")]. Unlike the Silverlight UTF for the browser and the Visual Studio desktop CLR unit testing tools, the Windows Phone UTF does not display TestProperty information within the test harness. Ignore Attribute The Ignore attribute can be used to temporarily exclude a specific test from execution. This can be useful for excluding a test that is blocking other tests from running. It allows you to retain compilation of the test, rather than merely commenting out the code. Note The number of tests listed in the unit test harness is unaffected by the Ignore attribute. Description Attribute The Description attribute is used on test methods and allows you to provide a string describing the purpose and/or behavior of the test method. The description is then presented beneath the title of the test result details screen on the phone (refer to Figure 22.4). The following example demonstrates the use of the Description attribute: [TestMethod]
[Description("An example test demonstrating the Description attribute.")]
public void ShouldAlwaysPass()
} Timeout Attribute The Timeout attribute allows you to specify an amount in milliseconds in which a test method must complete or the test method fails. The following is an example of using the Timeout attribute to prevent an asynchronous test method from taking longer than 100 milliseconds to execute: [TestMethod]
public void ShouldFailDueToAsyncTestTimeout()
} This test method fails because the call to EnqueueDelay delays the completion of the test by 1000 ms (1 second), and the Timeout attribute specifies that the test should take no longer than 100 ms. The EnqueueDelay attribute and the other asynchronous related attributes are discussed later in this chapter. Owner Attribute The Owner attribute is used to specify the person responsible for maintaining, running, and/or debugging the test. This attribute accepts a single string parameter, indicating the name of the owner, as shown in the following example: [TestMethod]
[Owner("Daniel Vaughan")]
public void ShouldAlwaysPass()
} The value of the attribute is not displayed within the test harness of the current Windows Phone UTF. ExpectedException Attribute Verifying that your code produces a correct response to a known set of values is one thing; verifying that it responds appropriately when given bad input is another. This is called negative testing, and it allows you to verify that code behaves correctly even when exceptional conditions arise. Ordinarily, if a test method raises an exception, the exception causes that test to fail. In a negative test, however, raising an exception may be the expected behavior. In that case, the ExpectedException attribute can be used to indicate that if an exception of a particular type, with a particular message, is not thrown, then the test should fail. The following example demonstrates the use of the ExpectedException attribute: [TestMethod]
public void ShouldFailDueToArgumentException()
    throw new ArgumentException("Invalid argument supplied.");
} Note The TagAttribute, AsynchronousAttribute, and BugAttribute are not available in the Microsoft desktop CLR test framework. Using any of them, therefore, means that your unit tests will not be compatible with the desktop CLR. Asynchronous Attribute The Asynchronous attribute informs the UTF that a test method should be considered to be in a running state until the SilverlightTest.EnqueueTestComplete method is called. Tip Use the Asynchronous attribute in combination with the Timeout attribute to prevent the test method from taking forever if it fails to call EnqueueTestComplete. For more information on the Asynchronous attribute, see the section “Asynchronous Testing.” Bug Attribute The Bug attribute allows you to associate a known bug with a unit test. Its key characteristic is that it reverses the result of a test, so you can first use it to demonstrate the existence of a bug, and once the bug is resolved, the Fixed property indicates that the test should pass. For example, if a method is able to reproduce a bug in the software, it may first look like this: [Bug("TFS 123")]
public void ExerciseBuggyCode()
    Assert.IsTrue(false); /* Simulates some broken code. */
} Consider the preceding test method. It passes because the Bug attribute’s Fixed property is false by default. When the issue is resolved, you can add the Fixed property to the Bug attribute, which removes the inversion behavior of the Bug attribute. [Bug("TFS 123", Fixed = true)]
public void ExerciseBuggyCode()
    Assert.IsTrue(true); /* Simulates issue resolved. */
} Priority Attribute Contrary to first assumptions, the Priority attribute is not used by the test system. Its purpose can be defined by you. It is, however, added to the set of implicit expression tags. The attribute requires an integer constructor argument, which specifies the priority value. For example: [TestMethod]
public void AlwaysPass()
    Assert.IsTrue(true, "Test method intended to always pass.");
} We can then use the tag expression Priority1 to execute this test method. SilverlightTest: The Base TestClass Type UTF test classes normally inherit from the SilverlightTest class. While inheriting from this class is not strictly required, it does provide for some advanced features such as asynchronous testing. Asynchronous unit test methods are a key feature of the UTF for Silverlight, and one that is notably absent from the Microsoft UTF for the desktop CLR. Note By inheriting from SilverlightTest, you lose compatibility with the Desktop CLR Visual Studio unit test framework. Therefore, do not inherit from this class if you want to retain cross-screen compatibility and do not require advanced UI testing facilities, such as asynchronous tests. Verifying Conditions with Assertions Assertions are the cornerstone of UTF. The Assert class has a multitude of test related method overloads that allow you to ensure the validity of your app’s state and behavior. The following is the core set of assertions used by most test classes: • AreEqual and AreNotEqual—These methods rely on the Object.Equals method to determine object equality. There are various overloads for primitives, as well as reference types. • AreSame and AreNotSame—Tests for whether two variables refer to the same object instance. These methods rely on the Object.ReferenceEquals method. There are various overloads for primitives, as well as reference types. • Fail—Allows you to explicitly fail a test based on logic within the test method. • Inconclusive—Allows you to explicitly set the outcome of a test to inconclusive. • IsTrue and IsFalse—Verifies that a Boolean value is either true or false. • IsInstanceOfType and IsNotInstanceOfType—Verifies that an object instance does or does not inherit from a specified type. • IsNull and IsNotNull—Verifies that an object is, or is not, null. If an Assert method fails, it raises a UnitTestAssertException, which is handled by the UTF infrastructure and reported back to you as a test failure. To complement the set methods provided by the Assert classes, there exists a CollectionAssert class with methods particular to collections, and a StringAssert class, which provides assertions based on regular expressions. Verifying Collection Conditions with CollectionAssert The following is the list of collection assertions that enable you to verify the contents of collections: • AllItemsAreInstancesOfType—Verifies that all items in a collection are, or inherit from, a specified type. • AllItemsAreNotNull—Verifies that no item in the collection is null. • AllItemsAreUnique—Verifies that a collection is a set; each item occurs only once. • AreEqual and AreNotEqual—Verifies that two collections have the same number of items, and that each item in the first collection is equal to the item at the same index in the second collection. • AreEquivalent and AreNotEquivalent—Verifies that two collections have the same number of items and that each item in the first collection has an item that is equal to it in the second collection. This differs from AreEqual and AreNotEqual in that order does not matter. • Contains and DoesNotContain—Verifies that a collection contains a specified item. • IsSubsetOf and IsNotSubsetOf—Verifies that all items in one collection exist in another specified collection. Verifying String Conditions with StringAssert The StringAssert class provides various methods for verifying the contents of strings: • Contains—Verifies that a string contains a specified substring. • Matches and DoesNotMatch—Uses a regular expression to verify that the specified string matches, or does not match, a specified pattern. • StartsWith and EndsWith—Verifies that a string starts or ends with a specified string. Hiding the Expressions Editor Sometimes you may like to execute your tests without having to interact with the UTF interface. It can be annoying to have to tap the Use Tag button to kick of the unit tests before the countdown timer reaches zero. Note Unfortunately, the test harness does not allow you to hide the tag expressions editor in the current version of the Windows Phone UTF. Nonetheless, it is shown here in anticipation of a future release of the UTF. To hide the tag expressions editor (in a future release) and to run the tests as soon as the test harness launches, you need to modify two properties in the UnitTestSettings class; set the StartRunImmediately property to true, and set the ShowTagExpressionEditor to false. This is demonstrated in this excerpt from the MainPage.xaml.cs file in the downloadable sample code: void OnLoaded(object sender, RoutedEventArgs e)
    SystemTray.IsVisible = false;
    UnitTestSettings settings = UnitTestSystem.CreateDefaultSettings();
    settings.StartRunImmediately = true;
    settings.ShowTagExpressionEditor = false;

    UIElement testPage = UnitTestSystem.CreateTestPage(settings);
    Application.Current.RootVisual = testPage;
    Application.Current.Host.Settings.EnableFrameRateCounter = false;

    mobileTestPage = testPage as IMobileTestPage;
} Testing Multiple Assemblies The current implementation of the UTF for Windows Phone does not support inclusion of tests from assemblies outside the test project; all tests must reside in the Windows Phone test project. When this shortcoming is rectified, if you want to have a single project for testing and include other test assemblies, add assemblies to the TestAssemblies collection of the UnitTestSettings class, as shown: UnitTestSettings settings = UnitTestSystem.CreateDefaultSettings();
UIElement testPage = UnitTestSystem.CreateTestPage(settings); Testing Non-Public Members Sometimes, you need to test classes and members that are not public but are internal to a project, such as during system testing, where you need to interact with UI elements directly. To have access to internal members, you must allow the test project access to the internal members of the main project. You do this by placing an InternalsVisibleTo attribute into the AssemblyInfo class of the main project, as shown: [assembly: InternalsVisibleTo("WindowsPhone7Unleashed.Tests.Silverlight")] The InternalsVisibleTo attribute accepts a single parameter, which is the name of the assembly. If the test project has a strong name, then the full name of the assembly must be used, including its public key token. Examples of the InternalsVisibleTo attribute are in the downloadable sample code.

You are currently reading a free preview of this book.


Sign up for a
Safari Library subscription
to access Rough Cuts.


Subscribe Now