Red11:01 with Jeremy McLain
The first phase of red-green-refactor is to write tests and make sure that they fail as expected.
In the TreeHouseDefense game, invaders move down a path. 0:00 Let's use driven development to write the code for the Path class. 0:04 Because we're using test driven development now, 0:07 we'll write the test first. 0:10 We'll first add a class to our test project named PathTests. 0:12 I'll clean it up a little bit, and then make the class public, so 0:23 that it can be accessed from the test runner. 0:26 Let's create a new test method. 0:31 So the first thing I'll do is say [Fact], and then public void, 0:33 and I'll name this test method MapLocationIsOnPath. 0:38 I've got a red squiggly here on fact, so 0:43 I use my quick action to add the using statement. 0:47 Now MapLocationIsOnPath will test the IsOnPath method of the Path. 0:52 So I'll first need to create a bunch of MapLocations for the Path. 0:59 Before I do that, I'll need to create a map object. 1:03 So I'll say var map = new Map (3, 3). 1:06 I need to fix my namespace here. 1:12 A MapLocation, pathLocations = 1:18 new MapLocation at, 1:25 I'll make this one 0, 1, 1:29 And I'll add a couple more. 1:39 So 1 at 0, or 1 and 1, 1, and 1 at 2, 1. 1:43 Now I'll create the instance of the Path class. 1:47 So I'll say var target = new Path, and it will take 1:51 the Path locations as a parameter, so pathLocations. 1:56 Now let's test calling the isOnPath method of the Path class. 2:03 So we'll say Assert.True(target.IsOnPath) 2:09 with a new MapLocation at 0, 1. 2:17 So this is the completed test for MapLocation IsOnPath. 2:23 But notice that we have these red squigglies here, 2:30 under the Path class name, that's because we don't have a Path class yet. 2:32 We can have Visual Studio generate the Path class for 2:37 us with the cursor on the red squiggles, 2:40 just hit Ctrl., on the keyboard to open up the Quick Actions Context menu. 2:42 Go down to Generate Type, and 2:48 here we see a few options for generating the Path class. 2:51 These first three will generate the Path class inside of our test project, 2:54 that's not what we want. 2:59 So go on to the fourth one, into Generate New Type, 3:00 then change the project to TreehouseDefense, and 3:03 have it create a new file called Path.cs, and hit OK. 3:08 As you can see, Visual Studio created the Path file, and 3:13 Path class in the TreehouseDefense project. 3:17 This is what it looks like. 3:21 Let's go back to our test code. 3:22 Now that we've generated the Path class, 3:23 we see a squiggly red line under the Is OnPath method. 3:27 Again, we can have Visual Studio generate this method for us. 3:31 Now the red squigglies are gone, and 3:34 we have a method named IsOnPath in the Path class. 3:36 With no red squigglies, our code will compile, and 3:39 we can have IntelliSense help us while we code the rest of the methods. 3:43 Let's create another test method to test when the map location is not on the path. 3:47 To do that I'll copy our existing test, 3:53 Paste it down here, and rename it MapLocation IsNotOnPath. 4:00 We change the assert to false, And we change this 4:07 MapLocation to something that's definitely not on the path, so make it 3, 3. 4:14 We could continue to write some more tests, but I think this is good enough for 4:18 right now. 4:22 One thing we should consider doing right now is removing some duplicate code. 4:23 Notice how both of these methods are almost identical, except for 4:28 the assert statement. 4:32 You might think that we should just combine these two tests into a single 4:33 method that has multiple assert statements. 4:37 This is problematic though because it isn't clear what's being tested, or 4:39 what causes the test to fail. 4:43 It's best to have two separate test methods with descriptive names like this. 4:46 Instead, we can move the creation of the map, the map locations array and 4:50 the Path, outside of the methods, and 4:54 create them in the constructor of the Path test class, so let's do that. 4:57 I'll create a constructor up here. 5:01 I'll say public PathTests, with no parameters, and 5:06 go down here, and we'll just copy this. 5:11 In fact, I'll cut them, and put them in here, and 5:18 no need to turn these into fields that the other methods can access. 5:23 So we'll say this one is, we'll call this one map, and we'll call it map3x3. 5:28 Because in the future, 5:35 we might have more than one map that our Path test class wants to use. 5:37 We can have Visual Studio generate this field in the path as class for us. 5:41 We'll do the same thing for Path locations, 5:46 except change this, so that it creates a new MapLocation array. 5:51 And we'll need to change these, so that they're using our map field, 6:04 so say map3x3, Copy that around, 6:10 And again, have Visual Studio generate this one for us. 6:23 Actually let's name this Path locations three, 6:28 since it's an array of three Path locations on the 3x3 map. 6:32 So to rename, I'll go Ctrl+R R, and 6:37 at the end here, I''ll just add a 3 there. 6:40 And we'll create a Path field named was, 6:45 just call it Path three. 6:50 For the same reasons, we named the PathLocation3, and it takes PathLocations, 6:53 And again, create field. 7:04 Okay, so now all the methods in the Path test class can access these fields. 7:09 So now, let's go down here, and use them. 7:16 I still like calling my target object, target, so 7:17 I'll keep that conventional, say var target = path3, and I'll fix this. 7:21 Same thing down here. 7:35 So there might be something we would be concerned about, that is, 7:51 we have two methods that can potentially alter our target object. 7:56 The problem with that is if one method alters the target object, and 8:03 then the other test method is called, 8:07 we might have some unexpected behavior in the next method. 8:09 What we want is there to be a clean slate, each time one of these methods is called. 8:14 So we want these three fields appear to be reinitialized every time 8:20 before each test method is called. 8:25 X unit actually handles this for us by creating a new instance 8:27 of Path test, before calling each one of these methods. 8:32 This allows us to use the constructor of Path test to set up each method. 8:37 Other unit test framework, such as NUnit and 8:43 MSTest have a special setup method that's called before each test method is ran. 8:45 Each test method should be completely independent of the other test methods. 8:50 In fact, xUnit runs test methods in a random order, so 8:55 that we can't count on methods being called in a certain order. 8:59 Now that we've cleaned up the test code, let's go ahead and run these tests. 9:02 To just run these two tests, 9:07 we'll just right click on PathTests, and then click Run Tests. 9:08 Let's check out the results in the test Explorer. 9:18 Looks like they both fail, let's get some more room by moving this pane down here. 9:20 So MapLocationIsOnPath, fails with the expected NotImplementedException. 9:29 However, if we look at MapLocationIsNotOnPath, 9:35 it fails with a different exception, it fails with the OutOfBoundsException. 9:39 That's not right, this is why we use red, green refactor. 9:44 We first run our test to make sure that they fail as expected. 9:48 If they don't fail the way we expect them to, 9:52 then there's probably something wrong with the test. 9:54 In this case, we're getting the wrong exception. 9:57 Something must be throwing an exception before we call the IsOnPath method. 10:00 Let's take a look. 10:06 I see the problem, I created a MapLocation that wasn't on the map, 10:15 that's why we're getting the out of bounds exception. 10:23 But this isn't what we're trying to test. 10:30 Let's make it a valid map location that's not on the Path, 0, 0 will do. 10:32 Now, we can rerun these tests. 10:41 We can do that by going into the Test Explorer, and 10:42 clicking on Run, Repeat Last Run. 10:45 Now, if we look at the Test Explorer, we see that they're both failing 10:50 with NotImplementedException, and that's what we expect. 10:54 Now, it's time to move on to the next step of making them all green. 10:57
You need to sign up for Treehouse in order to download course files.Sign up