Lab _06--- TDD SE 3730 / CS 5730 – Software Quality 1 Test Driven Development TDD: 1.1 Where have we been? Waterfall – Write all of the code before we do significant testing. o What is wrong with this method? Rational’s Unified Process (RUP) – A couple of major iterations of specify, design, develop and test. o Seems to work better than the Waterfall Method! TDD – Upside down development. o Do the test first then write the code – will this work? 1.2 Four Principles of TDD Write the test first Tests and compilers determine what we develop No code goes production without full set of unit tests Maintain the unit tests as part of the code 1.3 Unit tests are White Box tests --- Right??? What if we haven’t written the code yet are they still white box tests? A question for the philosophers! 1.4 How do we know whether a test is exhaustive? Famous philosophers have stated: “Anything that can break will break” “If you think you can develop fool proof code, a better fool will show up to prove you wrong” “If it hasn’t been tested its broken” Therefore, everything that can break must be tested. When in doubt, error on the “expect the worst”. Start with the goal of over testing and gradually relax this level if quality stays up. © 2011 Mike Rowe Page 1 2/9/2016 2:08 AM Lab _06--- TDD SE 3730 / CS 5730 – Software Quality 1.5 Write the Test First When you have a task to do (a method to implement), write the test first then the code. Don’t write all of the tests for a project then the code, but write a test for just the feature that you are going to work on next and then implement the code and so on. Small iterations! The emphasis is on writing a very small test and having each small test drive the development of very small piece of code. Then write another small test. 1.5.1 What is in a test Setup the preconditions Exercise the code/method Check the post conditions Teardown to cleanup system 1.6 No code goes production without full set of unit tests We have a test and we have code that makes the test pass. o It is now ready to check in and go into production. As our system gets more complex, many of the simple methods and classes will get changed and changed and changed – o What happens at this point? o They look ugly and will need to be simplified (REFACTORED) Having all the unit tests available that correspond to each of the added bits of functionality gives us confidence that we can rewrite the code without worrying about messing up some bit of functionality at breaking the system. It also lowers the risk in cleaning up code to make it more efficient, maintainable, extensible, etc. 1.7 Wake’s Traffic light metaphor Yellow – the test doesn’t compile classes and methods may need to be implemented. Red – the test compiles, but the code fails work on the code Green – the tests pass check the code in and go on to the next feature. Normal Cycle: 1. Start. (Green light!) 2. Write a test. 3. Try to run the test. It fails to compile, because the called routine hasn't been written yet. (Yellow light!) © 2011 Mike Rowe Page 2 2/9/2016 2:08 AM Lab _06--- TDD SE 3730 / CS 5730 – Software Quality 4. Write a stub for the new routine. 5. Recompile the test and the stub It now compiles 6. Try to run the test. It fails, because the stub doesn't do anything yet. (Red light!) 7. Write the body of the stubbed routine. 8. Recompile the test 9. Try to run the test. It passes. (Green light again!) Or is still needs work (Red light!) and the production code needs more work. Eventually it will work and go to (Green light) 10. Start the cycle again. Abnormal Conditions From Green to Green: The test passed right away. Either the test is bad, or you've already implemented the feature being tested. You might consider modifying the implementation just to see the test fail. (But see the "Refactoring" section below.) From Green to Red: The test failed right away. This is OK if it's a new test for an existing routine. From Yellow to Yellow: Oops - syntax error creating the stub. This can happen! From Yellow to Green: The test didn't compile without the stub, but adding the stub let the test pass. This is very suspicious: if a do-nothing stub makes the test work, is the test valid? From Red to Yellow: Oops - syntax error implementing the routine. This happens a lot! From Red to Red: New code didn't work. This happens to everyone - just fix the code. But - if it happens a lot, it's telling you to move to smaller tests (so you'll add smaller bits of new code as well). © 2011 Mike Rowe Page 3 2/9/2016 2:08 AM Lab _06--- TDD SE 3730 / CS 5730 – Software Quality 2 The Lab We are going to use the XP process to develop a linked list class using nano-iterations to get the feel for this process. The point of this lab is not to do some rocket science coding but to get a taste for TDD. 2.1 Define stories Each story defines a chunk of useful functionality. In class we will define these stories. Each story will define a linked list feature. Rule of thumb – the story should fit on a note card. 2.1.1 Stories – What are the stores possible for a linked list class. Each element shall consist of a node structure and the class shall consist of some of the below operations. IsEmpty( ) – determines whether a list is empty or not empty -- returns bool Length( ) – returns the number of nodes in a list -- returns int AddToHead( ) – adds a node to the front of the list AddToTail( ) – adds a node to the tail of a list CeateList() – creates a new linked list. Find( ) – returns the index (0 based) of the first node that contains the value specified or -1 if not found. GetNode( ) – returns the value stored in the specified node or Null if not found. DisplayNode( ) – display the node given its index DisplayList( ) – display the whole list DeleteNode( ) – deletes the specified node DeleteList ( ) – deletes the entire list SortList( ) – sorts the list by stored value. EditNode( ) – change the contents of a node based on node value or node index CopyNode( ) – copy the node at index1 to index2, if index2 is HEAD copy it to the head, if index2 is TAIL copy it to the tail of the list. BinSearch( ) – binary search of a sorted list for the index of a value. Each of these stories represents a nano-TDD iteration for the lab exercise. Standup meetings are common in XP and other Agile-based processes. The XP lore includes standup meetings as a mechanism for keeping meetings short and on point. 2.2 Release Planning Define what will go into each iteration. Very high-level design, for this lab we can just produce the list of features that we are going to implement. Some thought should go into the order in which we are going to implement them. A particular order may help in testing and implementing. © 2011 Mike Rowe Page 4 2/9/2016 2:08 AM Lab _06--- TDD SE 3730 / CS 5730 – Software Quality 2.3 Iteration Planning Each XP cycle begins with iteration planning to lay out the details for the current iteration. 2.3.1 Iteration One Based on the minimal complexity of this and subsequent iterations, iteration planning is simple. The tasks for this iteration’s plan include: 1. Define what the test needs to do, 2. Code the test, 3. Compile the test, 4. Execute the test to guide the development of the production code, and 5. Accept the production code by checking it into the CM system. 2.3.2 Define what the Automated Unit Test needs to do Based on the IsEmpty story, we specify the automated test to return a Boolean True when a tested linked list is empty (contains no nodes); otherwise, it will return False. Automated tests generally follow a pattern of setup, test, and teardown. For the setup, the test will need to create a linked list. Then it will call the IsEmpty method to see if it returns True. Finally, all objects created by the test are torn down by deleting the list. 2.3.2.1 We don’t want the test to do too much Later we will need to enhance the test when we developed functionality to add and delete nodes to and from the list. But we don’t need to do this now. We only implement enough test to get us through the current feature’s development, and we only implement enough functionality to make the test pass. 2.3.3 Coding of Test_IsEmpty 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 public bool Test_IsEmpty() { LinkedList list = new LinkedList(); if(list.IsEmpty()) { Console.WriteLine("Test_IsEmpty passed"); return True; } else { Console.WriteLine("Test_IsEmpty FAILED"); return False; } } // End of Test_IsEmpty © 2011 Mike Rowe Page 5 2/9/2016 2:08 AM Lab _06--- TDD SE 3730 / CS 5730 – Software Quality 2.3.4 Compilation of the Test The Test_IsEmpty code is compiled. The first compilation error occurs on the third line and relates to not having a class LinkedList to instantiate. This is a Yellow Light. It is the TDD practice of letting the compiler hint what code needs to be develop. The big hint is to create the shell/stub of the class LinkedList shell. The XP practice of keep it simple supports the notion that we do no more than necessary to move on to the next step. o This may seem radical, but it does inhibit feature creep by the hands of developers. So as a practice of extreme TDD we implement the trivial constructor like the below: Class LinkedList() { } This Class shell is sufficient to keep the compiler happy (for now) with line three. Compiling again produces an error on line five. We have gone from Yellow light to Yellow light, which is not unusual. The compiler directs us to implement the IsEmpty method of the LinkedList class. A simple/trivial solution consists of: public bool IsEmpty() { return true; } Compiling a third time allows the Test_IsEmpty unit test to compile. 2.3.5 Executing the test_isEmpty Executing the Test_IsEmpty unit test returns a True, indicating that the IsEmpty functionality exists, which is a Green light. Initially, having a Green light might sound like we are done, but Wake [5] indicates that we should normally go from Yellow to Red light, indicating that after the test case compiles the execution of the test should normally fail. Transitioning from Yellow to Green light with only the stubbed production code warns us that we may not be testing very much. We note this and continue to the next story. An alternative approach would be to add more teeth to the IsEmpty() method. o But, since we haven’t needed to designed or implemented beyond this to handle the IsEmpty() story we, as extreme TDD practitioners, would go on to the next story (linked list feature) and revisit this test later once it is necessary to really distinguish an empty © 2011 Mike Rowe Page 6 2/9/2016 2:08 AM Lab _06--- TDD SE 3730 / CS 5730 – Software Quality from an non-empty list, or when there is enough design and implementation done for us to design a Test_IsEmpty() test that can actually fail. o When we have code that can create a non-empty list we will need to add to the Test_IsEmpty() method. This is the completion of the first iteration. 3 Lab Assignment DUE: 3 Dec, NOON Deliverables for this lab: 1) As a group implement the IsEmpty 2) Select a set of linked list features, one for each team member. 3) Have a team meeting to settle on the order of stores to implement. 4) This assignment works well with at least three people and 2 computers. One computer and two people to do the TDD (sounds like Paired Programming); and one person and a computer to record the journal (see point #5). 5) Use SourceSafe to coordinate your progress. Check in each time you compile! 6) After each story, have a team meeting to decide what is next. 7) Each feature shall have a different team-pair implementing. Each team member must work in each of the roles (Pair-driver, Pair-shotgun, Journal recorder). 8) Record each compile and execution in a Tracking Sheet (see below) Journal progress, step by step, using the TDD method to implement the above. If in executing the test suite a test changes status or needs to be refactored, make sure this work gets journalized. Remember the minimal initial IsEmpty feature! The errors when compiling the test case (Refer to the Traffic Light model, state the colors) Errors in running the test case. 9) You might want to create a driver that calls each of the tests. For instance: TestMain( ). Or use Sharp Developer “#developer” http://www.icsharpcode.net/OpenSource/SD/ 10) Deliverables: a. A fine containing a final listing of your code (remember that the test cases are part of your code). b. A file containing a detailed SourceSafe history including differences! c. The journal documenting each compile and action taken as a result of the compile. d. A Project Report. © 2011 Mike Rowe Page 7 2/9/2016 2:08 AM Lab _06--- TDD SE 3730 / CS 5730 – Software Quality 4 Tracking Sheet Step Roles Story Comments/Description isEmpty( ) Traffic Light Green 1 2 isEmpty( ) Yellow 3 isEmpty( ) Yellow 5 isEmpty( ) Green length() Green Wrote test_isEmpty() - did not compile – no List Class defined wrote a List Class stub test_isEmpty() not compile – no isEmpty() method wrote a isEmpty() stub test_isEmpty() compiles and runs successfully ### did not transition from Yellow to Red probably implemented trivial solution. Start length() Yellow 6 Driver: Bubba Shotgun: Bo Recorder: Uno Driver: Bo Shotgun: Uno Recorder: Bubba 7 © 2011 Mike Rowe Start Wrote test_length() - did not compile – no length() method wrote length() stub. Page 8 2/9/2016 2:08 AM