Better Software - July/August 2008 - (Page 18) [Test] public void InitialListIsEmpty() { RecentlyUsedList list = new RecentlyUsedList(); Assert.AreEqual(0, list.Count); } [Test] public void AdditionOfSingleItemToEmptyListIsRetained() { RecentlyUsedList list = new RecentlyUsedList(); list.Add(“Aardvark”); Assert.AreEqual(1, list.Count); Assert.AreEqual(“Aardvark”, list[0]); } [Test] public void AdditionOfDistinctItemsIsRetainedInStackOrder() { RecentlyUsedList list = new RecentlyUsedList(); list.Add(“Aardvark”); list.Add(“Zebra”); list.Add(“Mongoose”); Assert.AreEqual(3, list.Count); Assert.AreEqual(“Mongoose”, list[0]); Assert.AreEqual(“Zebra”, list[1]); Assert.AreEqual(“Aardvark”, list[2]); } [Test] public void DuplicateItemsAreMovedToFrontButNotAdded() { RecentlyUsedList list = new RecentlyUsedList(); list.Add(“Aardvark”); list.Add(“Mongoose”); list.Add(“Aardvark”); Assert.AreEqual(2, list.Count); Assert.AreEqual(“Aardvark”, list[0]); Assert.AreEqual(“Mongoose”, list[1]); } [Test, ExpectedException(ExceptionType = typeof(ArgumentOutOfRangeException))] public void OutOfRangeIndexThrowsException() { RecentlyUsedList list = new RecentlyUsedList(); list.Add(“Aardvark”); list.Add(“Mongoose”); list.Add(“Aardvark”); string unreachable = list[3]; } Listing 4 Although there is a certain logic to procedural testing, the rationale is somewhat weak (even for procedural code). Testing individual methods in isolation doesn’t really make sense in terms of what a RecentlyUsedList is and how it is used. In many cases it is impossible to focus on just one method without involving others. For example, we cannot call the Add method without also having executed a constructor. Likewise, even in the constructor’s test, we still end up querying the Count property in order to say something meaningful about the result of construction. A per-method testing style also leads to an uneven spread of test-case length and depth. For example, most of what a RecentlyUsedList is about is covered by the Add method. A single test case for the Add method slops a number of different usage scenarios into one bucket. Indexing is also somewhat important, but unless we use Add we cannot usefully test the indexer. Indeed, much of the testing of Add’s behavior ends up in the indexer’s test! We can do better. A good unit test needs both to illustrate and define the behavioral contract of the unit in question. Behavior is more than just individual methods, so we need a style that cuts across the interface, a style where each test case is structured in terms of a meaningful and specific behavioral goal, as shown in listing 4. One of the more noticeable consequences of a behavioral style is the naming. The idea is that each method is named as a requirement and therefore provides an outline of the contract: • Initial list is empty. • Addition of single item to empty list is retained. • Addition of distinct items is retained in stack order. • Duplicate items are moved to front but not added. • Out-of-range index throws exception. Compare this rich description with the somewhat simplistic procedural summary: • Constructor • Add • Indexer As an aside, a behavioral style forms one cornerstone in behavior-driven development, which Dan North described in his Better Software article “Behavior Modification” [3]. In comparing the monolithic, arbitrary, procedural, and behavioral styles, we can see there is a great deal more to good unit tests than simply mastering the syntax of an assertion. {end} RefeRences: 1] Cockburn, Alistair. “The modern programming professional has GUTs.” alistair.cockburn.us/index.php/The_modern_programming_professional_has_GUTs. 2] Pryce, Nat; Freeman, Steve. “Are Your Tests Really Driving Your Development?” xpday6.xpday.org/programme.php#Are_Your_Tests_Really_Driving_Your. 3] North, Dan. “Behavior Modification.” Better Software magazine. March, 2006. What factors and styles have you seen that have influenced the quality of automated tests? Follow the link on the StickyMinds.com homepage to join the conversation. 18 BETTER SOFTWARE JULY/AUGUST 2008 www.StickyMinds.com http://alistair.cockburn.us/index.php/The_modern_programming_professional_has_GUTs http://xpday6.xpday.org/programme.php#Are_Your_Tests_Really_Driving_Your http://StickyMinds.com http://www.StickyMinds.com
For optimal viewing of this digital publication, please enable JavaScript and then refresh the page. If you would like to try to load the digital publication without using Flash Player detection, please click here.