So far, this chapter has examined the structure of the test environment and how test cases are nested within test classes in a test project. What remains is to look at the body of the test case and review how test cases either pass or fail. (When a test case is generated, you saw that an Assert.Inconclusive statement is added to the end of the test to indicate that it is incomplete.)
The idea behind unit testing is that you start with the system, component, or object in a known state, and then run a method, modify a property, or trigger an event. The testing phase comes at the end, when you need to validate that the system, component, or object is in the correct state. Alternatively, you may need to validate that the correct output was returned from a method or property. You do this by attempting to assert a particular condition. If this condition is not true, the testing system reports this result and ends the test case. A condition is asserted, not surprisingly, via the Assert class. There is also a StringAssert class and a CollectionAssert class, which provide additional assertions for dealing with String objects and collections of objects, respectively.
The Assert class in the UnitTesting namespace, not to be confused with the Debug.Assert or Trace.Assert method in the System.Diagnostics namespace, is the primary class used to make assertions about a test case. The basic assertion has the following format:
Assert.IsTrue(variableToTest, "Output message if this fails")
As you can imagine, the first argument is the condition to be tested. If this is true, the test case continues operation. However, if it fails, the output message is emitted and the test case exits with a failed result.
There are multiple overloads to this statement whereby the output message can be omitted or String formatting parameters supplied. Because quite often you won't be testing a single positive condition, several additional methods simplify making assertions within a test case:
AreSame: Tests whether two arguments refer to the same object
IsInstanceOfType: Tests whether an argument is an instance of a particular type
This list is not exhaustive — there are several more methods, including negative equivalents of those listed. Also, many of these methods have overloads that allow them to be invoked in several different ways.
The StringAssert class does not provide any additional functionality that cannot be achieved with one or more assertions via the Assert class. However, it not only simplifies the test case code by making it clear that String assertions are being made; it also reduces the mundane tasks associated with testing for particular conditions. The additional assertions are as follows:
Contains: Tests whether a String contains another String
DoesNotMatch: Tests whether a String does not match a regular expression
EndsWith: Tests whether a String ends with a particular String
Matches: Tests whether a String matches a regular expression
StartsWith: Tests whether a String starts with a particular String
Similar to the StringAssert class, CollectionAssert is a helper class that is used to make assertions about a collection of items. Some of the assertions are as follows:
AllItemsAreNotNull: Tests that none of the items in a collection is a null reference
AllItemsAreUnique: Tests that there are no duplicate items in a collection
Contains: Tests whether a collection contains a particular object
IsSubsetOf: Tests whether a collection is a subset of another collection
Sometimes test cases have to execute paths of code that can cause exceptions to be raised. While exception coding should be avoided, there are conditions where this might be appropriate. Instead of writing a test case that includes a Try-Catch block with an appropriate assertion to test that an exception was raised, you can mark the test case with an ExpectedException attribute. For example, change the CurrentStatus property to throw an exception if the PaidUp date is prior to the date the subscription opened, which in this case is a constant:
Public Const SubscriptionOpenedOn As Date = #1/1/2000# Public ReadOnly Property CurrentStatus() As Status Get If Not Me.PaidUpTo.HasValue Then Return Status.Temporary If Me.PaidUpTo.Value > Now Then Return Status.Financial Else If Me.PaidUpTo >= Now.AddMonths(-3) Then Return Status.Unfinancial ElseIf Me.PaidUpTo >= SubscriptionOpenedOn Then Return Status.Suspended Else Throw New ArgumentOutOfRangeException("Paid up date is not valid as it is before the subscription opened") End If End If End Get End Property
Using the same procedure as before, you can create a separate test case for testing this code path, as shown in the following example:
<TestMethod()> _ <ExpectedException(GetType(ArgumentOutOfRangeException), _ "Argument exception not raised for invalid PaidUp date")> _ Public Sub CurrentStatusExceptionTest() Dim target As Subscription = New Subscription target.PaidUpTo = Subscription.SubscriptionOpenedOn.AddMonths(-1) Dim val As Subscription.Status = Subscription.Status.Temporary Assert.AreEqual(val, target.CurrentStatus, _ "This assertion should never actually be evaluated") End Sub
The ExpectedException attribute not only catches any exception raised by the test case; it also ensures that the type of exception matches the type expected. If no exception is raised by the test case, this attribute will fail.
18.220.237.24