〃TestInsert: Empty structure is incorrect〃) End If item1。Insert(item2) toString = item1。ToString() Console。WriteLine(toString) If (item1。NextItem IsNot item2) OrElse _ (item1。PrevItem IsNot Nothing) Then Throw New Exception( _ 〃TestInsert: Item 1…》Item2 structure is incorrect〃) End If toString = item2。ToString() Console。WriteLine(toString) If (item2。NextItem IsNot Nothing) OrElse _ (item2。PrevItem IsNot item1) Then Throw New Exception( _ 〃TestInsert: Item 2…》Item1 structure is incorrect〃) End If item2。Insert(item3) toString = item2。ToString() Console。WriteLine(toString) If (item2。PrevItem IsNot item1) OrElse _ (item2。NextItem IsNot item3) Then Throw New Exception( _ 〃TestInsert: Item2…》Item1; Item3 structure is incorrect〃) End If toString = item3。ToString() Console。WriteLine(toString) If (item3。PrevItem IsNot item2) OrElse _ (item3。NextItem IsNot Nothing) Then Throw New Exception( _ 〃TestInsert: Item3…》Item2; structure is incorrect〃) End If toString = item1。ToString() Console。WriteLine(toString) toString = item2。ToString() Console。WriteLine(toString) toString = item3。ToString() Console。WriteLine(toString) Console。WriteLine(〃TestInsert: End〃) End Sub End Module …………………………………………………………Page 233…………………………………………………………… C H AP TE R 8 ■ L E AR N IN G AB O U T CO M P O N E N T O R IE N TE D A R CH I TE C TU R E 211 This test generates pretty output like this: ************** TestInsert: Start Me (item1) next(Nothing) prev(Nothing) Me (item1) next(item2) prev(Nothing) Me (item2) next(Nothing) prev(item1) Me (item2) next(item3) prev(item1) Me (item3) next(Nothing) prev(item2) Me (item1) next(item2) prev(Nothing) Me (item2) next(item3) prev(item1) Me (item3) next(Nothing) prev(item2) TestInsert: End The pretty output is not a verification of what went right。 Rather; the extensive output makes it simpler to perform postmortem debugging to understand why something failed。 In the TestInsert() method; a situation is created where three LinkedItem instances are instantiated: item1; item2; and item3。 Initially; the three items are not linked; but we use the Insert() method to link them into a structure; as shown in Figure 8…4。 Figure 8…4。 Testable doubly linked list structure But to get to the structure in Figure 8…4; some intermediate steps are required; and in the implementation of the method TestInsert(); those intermediate steps are tested。 The NextItem and PrevItem properties for each and every item are tested for the proper values at each step。 If some of the values don’t match; an exception is thrown to indicate an improper structure。 If an exception is thrown; the generation of the visual structure bees important。 As an aside; while developing the Insert() and Remove() algorithms; the visual structures and test code helped me figure out a bug。 The TestInsert() method is an example of an exhaustive test of a context。 The download able source code contains several other examples of exhaustive tests。 …………………………………………………………Page 234…………………………………………………………… 212 CH AP T E R 8 ■ L E A R N IN G AB OU T CO M P O N E N TO R IE N T E D AR C HI TE CT U R E DEBUGGING AND TESTING TOOLS Some of you might be thinking that to figure out why a test failed; you should use a debugger。 However; with proper tests that are part of an extensive testing framework and that generate extensive output; the need for a debugger is reduced。 Among the people who believe in a test…driven development (TDD) environment (including me); there is a question on the merits of a debugger。 According to Wikipedia’s Test…Driven Development entry (http://en。wikipedia。org/wiki/Test…driven_development); “Programmers using pure TDD on new (‘greenfield’) projects report they only rarely feel the need to invoke a debugger。 Used in conjunction with a Version control system; when tests fail unexpectedly; reverting the code to the last version that passed all tests may often be more productive than debugging。” A debugger is good for finding problems; but bad for understanding the nature of the problem。 Good tests verify scenarios。 The more scenarios; the more tests; and the more tested your code is。 If a particular scenario fails; you know that you have a problem。 And if everything was OK until you made a slight change that caused the tests to fail; you know you have a problem。 Test scripts are signposts that tell you what is working and what might not be working。 By using a debugger; you are often testing large chunks of code where you need to labor to find the bug。 A debugger has its uses; but when