Exercise 1: Red, Green…In this exercise, you will use the new features of Visual Studio 2010, which help support a TDD workflow. You will walk through Smart Tag actions, test runner enhancements, and navigation features. Task 1 – Creating a New ProjectIn this task, you will create a C# or VB Class Library and Test Project that will be used to explore the TDD features added to Visual Studio. - Open Microsoft Visual Studio from Start | All Programs | Microsoft Visual Studio 2010 | Microsoft Visual Studio 2010.
- From the Visual Studio Start Page click Projects and then click the New Project button.
.png)
Figure 1Creating the project - In the New Project dialog, select the Visual C# or VB project type. Make sure that .NET Framework 4.0 is selected, and then select the Class Library template.
- Change the name of the project to SimpleDataStructures, make sure the Create directory for solution checkbox is checked, and click OK.
The default target version of the .NET Framework in test projects is the .NET Framework 4. However, Visual Studio 2010 SP1 Beta adds basic support for unit tests that target the .NET Framework 3.5. For more information, see http://msdn.microsoft.com/library/gg442059.aspx. - Delete the default Class1.cs file (or Class1.vb) that the New Project Wizard created.
.png)
Figure 2Deleting the default file created by the New Project Wizard - In the Solution Explorer, right-click on the SimpleDataStructures solution and click Add | New Project… and select the Visual C# | Test or Visual Basic | Test project type. Make sure that .NET Framework 4.0 is selected, and then select Test Project.
- Change the project’s name to SimpleDataStructures.Tests and click OK.
- Delete UnitTest1.cs file (or UnitTest1.vb) that the New Project Wizard created.
.png)
Figure 3Deleting the default test file generated by the New Project Wizard (C#) .png)
Figure 4Deleting the default test file generated by the New Project Wizard (VB)
Task 2 – Defining a Context for the Tests.In this task, you will write a couple of tests to start driving out the design of your SimpleStack class. You will start by creating a new file to hold some tests for your SimpleStack class and then jump into writing out the first test. Along the way, you will use the new Smart Tag actions to help us wire up some of the necessary import statements, do some micro-code generation, and more. - From the Solution Explorer, right-click on the SimpleDataStructures.Tests project and select Add | Class. Be sure Visual C# Items | Code (or Common Items | Code for VB.NET) is selected and then choose the Class Template.
- Change the name to SimpleStackTests and click the Add button.
- Visual Studio will open the new SimpleStackTests.cs file (or SimpleStackTests.vb). Your solution should look like Error! Reference source not found.5
.png)
Figure 5The new SimpleStackTests.cs file(C#) .png)
Figure 6The new SimpleStackTests.vb file(VB) - Visual Studio automatically makes newly generated classes internal by default, but the class must be public in order for the Test Runner to find and run the tests. Add the public keyword as seen in the following code.
namespace SimpleDataStructures.Tests { public class SimpleStackTests
{ } } Visual Basic creates classes with public scope by default, and class files do not include namespaces unless you need to manually alter them from the default. Public Class SimpleStackTests
End Class - Next, you need to decorate this class with the TestClass Attribute so the Visual Studio Test Runner will recognize this class as a test fixture. Add the TestClass attribute to the SimpleStackTests class.
namespace SimpleDataStructures.Tests { public class SimpleStackTests { } } <TestClass()> Public Class SimpleStackTests
End Class - Notice there is a problem – Visual Studio does not know what the TestClass attribute is because the file is missing a using statement.
- You can use a new Smart Tag action, added in Visual Studio 2010, to automatically add the correct using (Imports if using VB.Net) statement. Press CTRL + . to trigger the Smart Tag context menu, and select the first option.
.png)
Figure 7Using the Smart Tag to add a missing using statement - You have a test fixture defined, but before you start writing tests, you need to get some context around what you will be writing the tests for.
“Context” in TDD is used for describing the current conditions and state of the SimpleStack. “Context” enables us to clearly describe what the test is meant to check. This is a great benefit in having the tests read like regular descriptive text instead of like software code. In addition, you are using longer and more descriptive names for the test fixtures and test methods. The goal is to communicate the essence of the requirement in the naming of tests, and let the test body (code) communicate the mechanics. While this may seem odd and go against some pre-conceived notions about writing code, it is common practice amongst many TDD & BDD practitioners. - Begin by assuming the stack has just been created, meaning it is in a default state. To set this context, rename the SimpleStackTests class to something more descriptive, like so:
public class WhenAStackIsCreated
{} <TestClass()> Public Class WhenAStackIsCreated
End Class
Task 3 – Writing the First Test: Designing and Defining the SimpleStackIn this task, you will start designing and building the SimpleStack class by writing a test using the context defined in Task 2. Along the way, you will use the new Smart Tag actions to help wire up some of the necessary using statements, do some micro-code generation, and more. - Begin by creating a new test method that specifies that a newly created stack should be empty. Decorate the method with the TestMethodAttribute. Note the relationship of the test class and test method names: WhenAStackIsCreated.ThenItShouldBeEmpty(). This naming convention helps us keep a clear understanding of what each test is checking.
(Code Snippet – TDD Lab - Ex1 ThenItShouldBeEmpty C#) [TestMethod]
public void ThenItShouldBeEmpty()
{
}
(Code Snippet – TDD Lab - Ex1 ThenItShouldBeEmpty VB) <TestMethod()> Public Sub ThenItShouldBeEmpty()
End Sub
- Next, you need to declare and initialize a new SimpleStack, and then verify that its IsEmpty property returns true. To begin, just declare and initialize a new SimpleStack.
[TestMethod] public void ThenItShouldBeEmpty() { SimpleStack theStack = new SimpleStack();
} <TestMethod()> Public Sub ThenItShouldBeEmpty() Dim theStack As New SimpleStack
End Sub - Notice that Visual Studio will again give you a Smart Tag, but for a different reason than before. In this case, Visual Studio does not know what the SimpleStack class is, so it will offer to generate a stub for you.
.png)
Figure 8Smart Tag options for an as-yet-undefined class (C#) .png)
Figure 9Smart Tag options for an as-yet-undefined class (VB) - Select Generate class for “SimpleStack” from the list (or Generate ‘Class SimpleStack’ if using VB.Net). A new window will open with a stub of the new class generated for you. Open the file called SimpleStack.cs or SimpleStack.vb from Solution Explorer.
.png)
Figure 10The generated stub of SimpleStack class(C#) .png)
Figure 11The generated stub of SimpleStack class(VB) The Smart Tag above has a second option, “Generate other…” which will open a dialog, allowing you to customize the to-be-generated code. Had you chosen that option you would have seen the following: .png) Take special note of the Project location option. By default, the Smart Tag will generate the stub code in the current project, but that may not be the behavior you desire. The Project location field gives you the ability to create the generated code in a completely different location. As an important side note, TDD purists will use the Smart Tag approach, generating the code directly in the same location where they are currently working. This subtle design approach encourages you the developer to make your fundamental design choices as late in the process as possible. In your small solution it is obvious where the generated code should live; however, in larger projects you might have 20 or 30 different components. Your code might need to be accessible by a number of different components. How can you know this early in the development cycle exactly which components may need access to the code you are developing? Leaving the decision of where to move the code until late in the cycle means you have gotten a much clearer picture of potential dependencies in the system, and are better able to make smart choices about where to place code you have written. All this falls back to the fundamental tenet: Do the simplest thing possible to make the test pass. (For more on the concept of making critical decisions at the last responsible moment, you highly recommend Tom and Mary Poppendeick’s Lean Software Development.) In this case, you triggered the Smart Tag from within your SimpleDataStructures.Tests project, but you likely want the SimpleStack implementation to live in the SimpleDataStructures project and namespace. You could have done that by selecting the corresponding Project Location in this dialog. - Going back to the test, you will verify that the stack is empty by asserting its IsEmpty property is true.
[TestMethod] public void ThenItShouldBeEmpty() { SimpleStack theStack = new SimpleStack(); Assert.IsTrue(theStack.IsEmpty);
} <TestMethod()> Public Sub ThenItShouldBeEmpty() Dim theStack As New SimpleStack Assert.IsTrue(theStack.IsEmpty)
End Sub - Again, you will see a Smart Tag, this time offering to Generate property stub for IsEmpty in SimpleDataStructures.Tests.SimpleStack. Selecting this option will generate a public auto-Property in the SimpleStack class.
.png)
Figure 12The Smart Tag showing the option to create a method stub(C#) .png)
Figure 13The Smart Tag showing the option to create a method stub (VB) - Move to the SimpleStack.cs file (or SimpleStack.vb) and you will see the stubbed property.
.png)
Figure 14The stubbed IsEmpty property (C#) .png)
Figure 15The stubbed IsEmpty property (VB) - Now run the test by right-clicking the test method and selecting Run Tests (or type Ctrl+R, T). You should observe the assertion that IsEmpty returns true fails, and therefore, the test fails too.
- In TDD fashion, you will now do the simplest thing possible to get the test to pass, you will simply return true for the getter!
This may seem a silly, non-sensical step; however, it is critical for a number of reasons. First, you are checking the test you just wrote. If your test does not pass, then you have created an error in your test – checking for false when you may have meant to check for true, for example. Secondly, this enforces the concept of doing the simplest thing possible to make the test pass. As part of doing the simplest thing possible, you also changed this from an auto-Property, which is both read and write, to a read-only Property. You did this because it is the minimum functionality, and code, required to pass the test. The test does not specify having to write to the stack, so you are not going to allow your code to have that functionality. You are keeping the code lean, which improves legibility and decreases your exposure to bugs. (Less code == less chance for bugs!) class SimpleStack { public bool IsEmpty { } } (Code Snippet – TDD Lab - Ex1 IsEmpty Returns True VB) Public Class SimpleStack Public ReadOnly Property IsEmpty() As Boolean
Get
Return True
End Get
End Property
End Class - The next step is to go back to the test; however, you do not need to move your hands off the keyboard and reach for the mouse. Instead, use the new Quick Search features to navigate the code base in just a few key strokes. Hit CTRL + , (that is Control and a comma) to trigger the Quick Search dialog, and then start typing the name of a File, Class, or Method. Quick Search will filter the list of available locations in the code base for you. When you have filtered enough and located the spot in the code you want to go, use the Up and Down arrow keys to highlight the option, and hit the Enter key.
.png)
Figure 16Use Quick Search to navigate directly to a particular method Visual Studio will navigate to that location in the code base, place the cursor at the start of the Class or method name, and you are ready to go! - Now that you are back in the test method, go ahead and re-run the test. This time it should pass!
.png)
Figure 17The test passes!
Task 4 – Adding More Functionality Driven by TestsAt this point, you have a nearly empty shell of a SimpleStack implementation. There is only one working member: a read-only property. You can continue adding functionality by driving out the design with tests. Now, look to add the ability to put items onto, and take items off the SimpleStack. - Add a new test that specifies a new method on SimpleStack, the Push method, which takes in an integer:
(Code Snippet – TDD Lab - Ex1 ThenShouldBeAbleToPushAnItemOntoTheStack C#) [TestMethod]
public void ThenShouldBeAbleToPushAnItemOntoTheStack()
{
var theStack = new SimpleStack();
theStack.Push(1);
}
(Code Snippet – TDD Lab - Ex1 ThenShouldBeAbleToPushAnItemOntoTheStack VB) <TestMethod()> Public Sub ThenShouldBeAbleToPushAnItemOntoTheStack()
Dim theStack As New SimpleStack
theStack.Push(1)
End Sub
- Under the Push method call, you should notice a Smart Tag. Trigger the Smart Tag by hitting CTRL + . and you will see it is offering to generate a method stub for the Push method. Hit Enter and let Visual Studio generate the stub.
.png)
Figure 18Use the Smart Tag to generate method stubs(C#) .png)
Figure 19Use the Smart Tag to generate method stubs(VB) - Now run the test and make sure it fails.
It may seem odd to run the test at this point because you know the code that Visual Studio stubbed in for us should cause the test to fail. However, an important part of TDD is the cadence of Red – Green – Refactor, and a key step in that cadence is making sure the test actually does fail, as you expect. Why is this key? Because there will inevitably be cases where a test passes by coincidence, despite what you know should happen. In those cases, you need to make sure your tests are specifying the correct behaviors and fix them if not. - Your new goal is to get this test to pass. Being true to TDD, you will do the absolute simplest thing you can to get the test to go green: you will get rid of the NotImplementedException in the Push method! At this point, you are not going to add any implementation in the method – the test you have only checks that you can successfully push something on to the stack.
internal void Push(int p)
{
}
Sub Push(ByVal p As Integer)
End Sub
- Navigate back to the test using Quick Search (CTRL + ,) by entering “TSBA” into the search box.
- Notice that Quick Search will filter the results by matching the capital letters TSBA to the capital letters in the test name you are looking for – ThenShouldBeAbleToPushAnItemOntoTheStack.
.png)
Figure 20Use Quick Search to filter and navigate using just the capital letters of a class, method, or file name - Re-run the test and it should pass. Green! Unfortunately, the push method is not very useful at this point, so you will work on that next.
Next StepExercise 2: Refactor! | |