饭饭TXT > 学习管理 > 《Visual Studio 2010 高级编程(英文出书版)》作者:Nick Randolph/等【完结】 > [Visual.Studio.2010.高级编程].Professional.Visual.Studio.2010.txt

第 32 页

作者:Nick Randolph/等 当前章节:15397 字 更新时间:2026-6-18 14:51

recognizes this as a test project and automatically analyzes it for any test cases in order to populate

the various test windows.

Classes and methods used in the testing process are marked with an appropriate attribute. The

attributes are used by the testing engine to enumerate all the test cases within a particular assembly.

TestClass

All test cases must reside within a test class that is appropriately marked with the TestClass

attribute. Although it may appear that there is no reason for this attribute other than to align test

cases with the class and member that they are testing, you will later see some benefits associated

with grouping test cases using a test class. In the case of testing the Subscription class, a test class

called SubscriptionTest was created and marked with the TestClass attribute. Because Visual

Studio uses attributes to locate classes that contain test cases, the name of this class is irrelevant.

However, adopting a naming convention, such as adding the Test suffix to the class being tested,

makes it easier to manage a large number of test cases.

TestMethod

Individual test cases are marked with the TestMethod attribute, which is used by Visual Studio

to enumerate the list of tests that can be executed. The CurrentStatusTest method in the

SubscriptionTest class is marked with the TestMethod attribute. Again, the actual name of

this method is irrelevant, because Visual Studio only uses the attributes. However, the method

name is used in the various test windows when the test cases are listed, so it is useful for test

methods to have meaningful names. This is especially true when reviewing test results.

additional test attributes

As you have seen, the unit-testing subsystem within Visual Studio uses attributes to identify test

cases. A number of additional properties can be set to provide further information about a test case.

This information is then accessible either via the Properties window associated with a test case or

within the other test windows. This section goes through the descriptive attributes that can be applied

to a test method.

Description

Because test cases are listed by test method name, a number of tests may have similar names, or

names that are not descriptive enough to indicate what functionality they test. The Description

attribute, which takes a String as its sole argument, can be applied to a test method to provide

additional information about a test case.

Your first Test Case .

201

owner

The Owner attribute, which also takes a String argument, is useful for indicating who owns, wrote,

or is currently working on a particular test case.

Priority

The Priority attribute, which takes an Integer argument, can be applied to a test case to indicate

the relative importance of a test case. Though the testing framework does not use this attribute, it is

useful for prioritizing test cases when you are determining the order in which failing, or incomplete,

test cases are resolved.

Test Categories

The TestCategory attribute accepts a single String identifying one user-defined category for

the test. Like the Priority attribute the TestCategory attribute is essentially ignored by Visual

Studio but is useful for sorting and grouping related items together. A test case may belong to many

categories but must have a separate attribute for each one.

Work items

The WorkItem attribute can be used to link a test case to one or more work items in a work-itemtracking

system such as Team Foundation Server. If you apply one or more WorkItem attributes to a

test case, you can review the test case when making changes to existing functionality. You can read

more about Team Foundation Server in Chapter 57.

ignore

It is possible to temporarily prevent a test method from running by applying the Ignore attribute to

it. Test methods with the Ignore attribute will not be run and will not show up in the results list of

a test run.

You can apply the Ignore attribute to a test class as well to switch off all of the

test methods within it.

Timeout

A test case can fail for any number of reasons. A performance test, for example, might require

a particular functionality to complete within a specified time frame. Instead of the tester having

to write complex multi-threading tests that stop the test case once a particular timeout has been

reached, you can apply the Timeout attribute to a test case with a timeout value in milliseconds, as

shown in the following code. This ensures that the test case fails if that timeout is reached.

202 .

chaPter 11 uniT TeSTing

Vb

<TestMethod()>

<Owner(“Mike Minutillo”)>

<Description(“Tests the functionality of the Current Status Property”)>

<Priority(3)>

<Timeout(10000)>

<TestCategory(“Financial”)>

Public Sub CurrentStatusTest()

Dim target As Subscription = New Subscription

Dim actual As Subscription.Status

actual = target.CurrentStatus

Assert.AreEqual(Subscription.Status.Temporary, actual, _

“Subscription.CurrentStatus was not set correctly.”)

End Sub

Code snippet SubscriptionTests\SubscriptionTest.vb

c#

[TestMethod()]

[Owner(“Mike Minutillo”)]

[Description(“Tests the functionality of the Current Status Method”)]

[Priority(3)]

[Timeout(10000)]

[TestCategory(“Financial”)]

public void CurrentStatusTest()

{

Subscription target = new Subscription();

Subscription.Status actual;

actual = target.CurrentStatus;

Assert.AreEqual(Subscription.Status.Temporary, actual,

“Subscription.CurrentStatus was not set correctly.”);

}

Code snippet SubscriptionTests\SubscriptionTest.cs

This snippet augments the original CurrentStatusTest method with some of these attributes to

illustrate their usage. In addition to providing additional information about what the test case does

and who wrote it, this code assigns the test case a priority of 3 and a category of “Financial”.

Lastly, the code indicates that this test case should fail if it takes more than 10 seconds (10,000

milliseconds) to execute.

assertinG the facts

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

asserting the facts .

203

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

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:

Vb

Assert.IsTrue(variableToTest, “Output message if this fails”)

c#

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.

This statement has multiple overloads 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:

.

IsFalse: Tests for a negative, or false, condition

.

AreEqual: Tests whether two arguments have the same value

.

AreSame: Tests whether two arguments refer to the same object

.

IsInstanceOfType: Tests whether an argument is an instance of a particular type

.

IsNull: Tests whether an argument is nothing

This list is not exhaustive — several more methods exist, 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

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:

204 .

chaPter 11 uniT TeSTing

.

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

the collectionassert class

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 no duplicate items exist in a collection

.

Contains: Tests whether a collection contains a particular object

.

IsSubsetOf: Tests whether a collection is a subset of another collection

the expectedexception attribute

Sometimes test cases have to execute paths of code that can cause exceptions to be raised. Though

exception coding should be avoided, conditions exist 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:

Vb

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

Code snippet Subscriptions\Subscription.cs

asserting the facts .

205

c#

public static readonly DateTime SubscriptionOpenedOn = new DateTime(2000, 1, 1);

public Status CurrentStatus

{

get

{

if (this.PaidUpTo.HasValue == false)

return Status.Temporary;

if (this.PaidUpTo > DateTime.Today)

return Status.Financial;

else

{

if (this.PaidUpTo >= DateTime.Today.AddMonths(-3))

return Status.Unfinancial;

else if (this.PaidUpTo >= SubscriptionOpenedOn)

return Status.Suspended;

else

throw new ArgumentOutOfRangeException(

“Paid up date is not valid as it is before the subscription opened”);

}

}

}

Code snippet Subscriptions\Subscription.vb

Using the same procedure as before, you can create a separate test case for testing this code path, as

shown in the following example:

Vb

<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 expected = Subscription.Status.Temporary

Assert.AreEqual(expected, target.CurrentStatus, _

“This assertion should never actually be evaluated“)

End Sub

Code snippet SubscriptionTests\SubscriptionTest.vb

c#

[TestMethod()]

[ExpectedException(typeof(ArgumentOutOfRangeException),

“Argument Exception not raised for invalid PaidUp date.”)]

public void CurrentStatusExceptionTest()

{

206 .

chaPter 11 uniT TeSTing

Subscription target = new Subscription();

target.PaidUpTo = Subscription.SubscriptionOpenedOn.AddMonths(-1);

var expected = Subscription.Status.Temporary;

Assert.AreEqual(expected, target.CurrentStatus,

“This assertion should never actually be evaluated“);

}

Code snippet SubscriptionTests\SubscriptionTest.cs

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 cause the test to fail.

initializinG and cleaninG uP

Despite Visual Studio generating the stub code for test cases you are to write, typically you have

to write a lot of setup code whenever you run a test case. Where an application uses a database,

that database should be returned to its initial state after each test to ensure that the test cases are

completely repeatable. This is also true for applications that modify other resources such as the file

system. Visual Studio provides support for writing methods that can be used to initialize and clean

目录
设置
设置
阅读主题
字体风格
雅黑 宋体 楷书 卡通
字体大小
适中 偏大 超大
保存设置
恢复默认
手机
手机阅读
扫码获取链接,使用浏览器打开
书架同步,随时随地,手机阅读
首 页 < 上一章 章节列表 下一章 > 尾 页