 My wife would be I'm very unhappy if I left it somewhere. Okay. All right. We've just made we've just made nine has two factors pass What happens if we do ten? but Can we get another failing test? Does anybody think we can get another failing test? No, I think the algorithm is done Okay, now if I didn't think it was done. I would write more tests Until I was comfortable with and this one's kind of tricky. So I might jump ahead and do a hundred I Might do some more just to make myself feel a little better Okay, but I'm pretty confident that there's the algorithm Can we do anything to that algorithm? Okay, there's the algorithm and there's duplication in here This is the second half of the course is Learning how to spot duplication. So what's our problem? We could do that if we're if performance is our problem This is what we have Just move to the same Yeah, well never gonna be greater than one. It can never be greater than one All right, it can never be so if I leave this code in It just makes that algorithm harder to read This is the kind of stuff that you want to get rid of this is the part that people say, you know You're saying okay, but it's done dead simple This is the part where you think This is where your brain has to work so we're gonna get rid of that line and Go away line and if I run the tests. All right, so make that change quickly Get rid of that line and then we're done We have just done Bob Martin's caught a prime factors caught it I was at Agile 2004 I think it was and I was sitting next to Ken our and Richard Gabriel who knows Richard Gabriel and And not the singer Nobody oh Peter Gabriel Richard Gabriel Richard Gabriel was one of the open-source guys anyway. He became a poet. He's taught at Stanford for years He suddenly decided to become a poet after being a programmer for years So he went to school to become a poet and then came and taught us and one of the stories he told us was To become a poet I had to write the same poem a thousand times He wrote that same poem. It's a little poem that was the poem that got him his PhD in In poetry and he had to write it a thousand times over and over and over and over again So he said Everybody in the room who has programmed something? Twice the same thing twice raise their hand. Let's do that Okay, I was sitting next to Ken our and I got my hand up. I'm proud They says everybody is keep your hands up. Just keep your hands up for a second. Everybody's who programmed the same thing three times Who that looks good four times? Five times Wow six times seven times eight times nine times And my hand went down about then Ten times this what? Yeah, I actually But I was sitting next to Ken our and about ten everybody else's arm was down in the room including mine and Ken ours was still up and About 2017 Ken ours came hand came down. I went home on the airplane. I wrote hello world a bunch more times Just go so I could leave it up longer the point is We need to practice What we do and if we practice on greatly huge hard problems if we rewrite the same thing We need to practice on a little thing and Bob Martin has put one of these together. It's on the web Just look up Uncle Bob Uncle Bob prime factors. All right and run through this one. He's got another one the bowling the bowling game Highly recommended fun, and it's got a little bit more. It's a little harder than this one All right, that's homework all right, so What happened to my computer I Got the point That's all right. I think yeah, yeah, it's not Your pointing device has to be a direct a line of sight All right, I want to skip I'm gonna skip the exercise what we're doing skip this particular exercise. We'll come back to it. I hope but I want to do is Can't see that far Okay, so the question I get all the time is was John I can't do this and I say why can't you do this? So somebody tell me what we can't test just name something we can't test this just say it We can't test nuclear weapon detonation Okay, that's a good one. What'd you say? Okay, okay, but yeah, but you don't get to talk All right, nobody thinks there's not there's something we can't test Real-time systems, okay, so so the people say John. I can't test it. It's legacy code It looks like that Not possible And that's good legacy code Yeah, so that's what I want to hear those things The one the one I really hear the people that really grumble are they say well legacy code is one of them Because it's too ugly the next one they say is I can't test gooey's I can't test nuclear Nuclear launch launching, okay, it turns out we can you're gonna be up in a sec it turns out we can and Richard is about to show us how the thing is that what's important to be able to test legacy systems because I don't know Who gets to work on clean code or beginning code? From scratch when's the last project you did? Greenfield thank you greenfield All right. Are you working on it now? Were you working on it last year greenfield? Yeah, see that all the hands go down So we don't get to work on greenfield very often when we do we like yes, yes But it guess how long it takes to turn greenfield Untested greenfield code into legacy code So Richard is a little short One month Jim shore says three months Okay, and I'd rather side with Richard on this one, but Jim shore says three months So if you've been on your greenfield Development and haven't been writing tests for three months You've got legacy code Okay, that's that's just the way it is Okay, that's that's the fact legacy code defined by James grinning is any code that's untested and By the time three months goes by there's gonna be enough bricks and rocks falling down in little odd places That you probably you probably wanted yours testing if you go longer than that it's gonna cost you a lot to get those tests in Alright, so what do we do to help our legacy code out? the One of my favorite things is don't be afraid that you want to get inside just get inside Go inside take small steps Okay, and there is a light luckily in the middle of this pyramid. There is a light at the end of that the other thing we want to do is Make sure we get lots of shoring and make sure we get Scaffolding up Okay, lots of it. All right, that's what we do how we deal with legacy code All right, Richard has got And you guys see that good Okay, so what we're looking at here is just a really dumb little application that is an address book I can add an address and This is existing code legacy code This what we're gonna do is we're gonna write a test for the behavior that's on this ad address dialogue You notice that this okay button is disabled Until I type some text in the first name field That's the behavior That we're going to unit test We're gonna write a test that says the okay button should be disabled when the field is empty And it should be enabled when the field has some text in it Because that's the existing behavior that I have on this dialogue I want to write a test to cover the existing behavior Because then we're going to add some new behavior and I want to make sure the new behavior I add does not break the old behavior So that's the application. It's really quite stupid Let's go over here and take a look at the existing code on the form And you see in here there's a handler for the text changed event on that first name text box And he just says yeah got to have non empty text For that okay button to be enabled whenever the text has changed. I'm gonna keep setting that so what we're gonna do is We're gonna move this behavior to another class and the reason we want to do that is because This class is a form And it has controls on it and they all get created whenever this form gets created it by initialized component and Creating the controls involved looking up all these resources and setting all these attributes on the individual controls That means instantiating this class is expensive And we want our unit tests to run fast because we're gonna end up with hundreds and thousands of thousands and thousands of unit tests After we work on this thing for five years, right? We're gonna have all kinds of unit tests. We want them to run fast So that every time we make a change. It's quick to get an answer to that question of did I break something? So we're gonna make a new class What I'm gonna follow is something called the mediator pattern a mediator class It's just a class that coordinates the interaction of other objects So I'm gonna add a class called add address form mediator Okay, got that class That's fine. I'm gonna add a test project to my solution oops add new project It's going to be a C-sharp class library and I'm gonna call it test add Test address book So all I'm doing so far is just getting like my test this this is legacy code It doesn't have any tests on it, right? So I'm just getting my test framework set up That makes a time made a Project to hold my tests. You always want to keep your test code separate from your production code So that your production code doesn't ever accidentally become dependent on your tests because you're not gonna ship your tests You're gonna ship your production code only So on my test project here I'm gonna add a reference to the end unit framework so I can use it to write my tests and The first time add reference runs always takes a while isn't DC-sharp guys, I'm sure you know you can't see it but my hard drive lights on solid here. We go and unit framework Okay, I don't need this data and XML link stuff We're not gonna be doing any of that. I'm gonna call this class test add address form mediator You name your class your test classes and your test files anything you want. I like to Make it obvious what I'm trying to test Just from the name so this thing is going to be a test fixture because it's going to be a class that holds tests These little pop-up boxes you're seeing are coming from a sharper which is helping me fill in stuff and The first test I like to write for a new class I like to call it construct and it basically is my one-stop shop for finding out how to make an instance of this class So I'm gonna say add address form mediator and do oops This class needs to be public so I can see it from my test and I need to reference Added my I needed to add a reference to my production code. So I added that made my test code refer to my production code and Imported its name space and I'm just going to say Assert that is not null mediator And this little message I'm writing is just for me now you notice. I didn't say new class name. I said That get instance The reason I do that is I like to do what's called encapsulating construction on the classes that I write hide the constructor You might say why do you why do you bother to do that? Well, I do that so that if suppose at some later date This guy needs to be a singleton and everybody needs to use the same exact instance or Suppose I need to do some kind of special thing every time one of these objects is created But the callers that are getting these instances don't need to know about that So by decoupling myself from the direct use of the constructor I'm able to localize any of those decisions right here inside this Something I encounter often is sometimes you do what you call to phase initialization Where there's certain things that don't work right if you do it try to do it from the constructor But it will work if you do it on any other method. So I'll do the constructor and then do the The second phase initialization inside here. So again, I encapsulated that inside this method all the guys that are using this class Don't need to know about that So let's go back to look at our test. I've got a test here that says how to make an instance I Can build this code Build succeeded and go over here to end unit. I'll load up My test framework my test assembly so that's a test bin debug. Here's my test assembly loads that up I've got one test here. I run that test My test is green now. I kind of cheated because I went off and I implemented the Implemented this get instance right as I was writing it because I knew I'm kind of doing that I know exactly what I want some kind of stiffness skipping a step. I didn't quite strictly speaking have a red test So now I've got this mediator What I want to do is I want to start moving this behavior from this form Off on to the mediator. So I know I know that the form is gonna need a mediator because that's where all the work Is gonna happen and this is the behavior that I want to move so instead of doing that I'm gonna say mediator first name text changed now This is the thing that I want to have You know Implement the behavior on you know, that's gonna interact with my form. So I'm gonna have to stub that out And I'm gonna say not implemented exception because what I want to do keep that around What I want to do is write a test That says what that first name change should do so the test is Okay enabled when first Name not empty. So I say mediator dot I have to make a mediator mediator dot first Name text change. That's the production code that I want to call and now I need to assert something here. I need to say You know it is true that on a on the form that the okay Enabled property was set And I want to say that not only was it set But the last value it was set to was true now. I don't have a form yet. So how am I gonna? How am I gonna do that? Let's have the mediator talk to the form through an interface So I'm just gonna make an interface. I Don't know how I'm gonna get one yet. I don't even know what this interface is, but I know it's gonna be Something that our real form will have to implement So I know this Kind of getting what let's let's do this I'm going to The mediator is gonna have to talk to the form. So let's get that Adjusted here. So we know that this mediator is gonna have to collaborate with the form Which is where all the controls live because he is gonna orchestrate the interaction between the controls so what we're gonna do is have an interface that Handles all those interactions for the mediator now in my test I've got I'm I've got it written here that you know I've got this interface and then I've got some things down here that I want to know for my test But these are not things that I want to expose in my production code So really what I want in my test is I want some kind of stand-in for the real form because remember the whole Reason we're moving this to another class in the first place is I don't want to instantiate that real form Because it's a heavyweight. So I'm gonna make a fake form For this fake form. It's gonna have to be a class It's gonna have to implement the interface that the production form uses which we don't know what that interface is yet We're gonna do this encapsulation stuff on it just like we did before These are the things we want to know about how the mediator interacted with the form So we know that these have to be properties on our fake. They're things that are fake is gonna tell us We don't know what they're gonna. We don't know what they're gonna do yet But these are the things that we want to know In our test. Okay, so at this point Resharper is telling me hey, you didn't give me a form up here. Okay fine. I'll do the simplest thing to get that test to compile and Over here, I'm gonna do the simplest thing just to get him to compile oops Okay, so our build succeeded. We've got a failing test Okay, we've got a failing test because our stand-in form doesn't really do anything except Throw not implemented exceptions yet So let's see if we can Do a little something on here we know that What we really wanted to have happen over here If we go back and look at our production code that we're trying to get covered by tests. This was the old This was the old behavior right here is that he was Setting the enabled property of the okay button and he was reading the text property of the first name text box control So those are good candidates for what we need to have on this interface for our fake and our production form so Let's go over here to Our mediator, let's take this interface and we're gonna say Public bool Okay enabled and he's gonna have a setter Because that's all we need Oh, it's an interface. It's only public and he's going to access The first name text at with a getter So I so based on our existing production code These are the kinds of interactions that the mediator needs to have with the form so Let's take this. I'll just move that off to its own File, okay, so we have the form interface. We have the mediator and We know that the production form has to Implement that interface and we know that This mediator needs to talk back to the real form. So when we construct the mediator, we're going to use the Production implementation of this interface I'll stub out the implementation of the interface right now I'm just going to leave these With not implemented and we'll come back to them in a minute because we're going to we're focusing on the mediator first But I want this all this code to compile so I'm going to come back over here to the mediator and This was The production code that we had and then his first name text changed We're just going to steal that Implementation by pasting it in and then saying well instead of accessing the enabled property on that control directly Now I'm accessing that same thing through the form and ditto for the first name text So now I've moved that production code from the dialogue where it was sitting directly in the event handler I've moved it over here to the mediator The mediator is interacting with those controls through an interface and the reason we want To do that extra level of indirection is so that when we write our tests we can write a fake That stands in for the real form and he's going to say oh, yeah My first name text is empty and my okay button is not been set yet And he's going to he's going to record the interaction of the mediator with the controls in the test scenario So if we come back here and look at our test We should now have We have our fake form. He doesn't yet Oh, he's not implementing the members of the interface yet So now we'll put the implementation on the fake. What does the fake want to do? The fake wants to do two things. He wants to remember all the things that were done to him So that you can in your test you can write assertions and say when I talked to them I told the mediator to do something did he interact with the fake form in the right way did he do the things to the fake form that he was supposed to do and and Did so that's the one thing you want to remember what you do to the fake form so in this case we want to remember that we called the Setter on the okay enabled property you want to remember the last value that was set on it so I'm going to make some backing store for these and then my Accessors that I had written had stubbed out are going to now return those values We also want to remember The same thing for the first name text Except in this case. It's a getter. So a getter Now on a fake has to return what I like to call a lie your fake objects are going to lie to your production code to force the production code Down the code path that you want to test So I'm going to have to return something here. I'm just going to return To make my first test pass. I'm just going to return a string a fixed string and I'm going to put a getter on that property to follow any conventions So up here we learned that based on the remember we're writing a covering test here We're not writing a test for new functionality. We're writing a test to try to cover the behavior of existing functionality And so it's okay to cheat When writing the test and look at this and say this is the production behavior I want to call or I want to cover there's two things that happened here. It did a set property on one Part of the form and it did a get property on the other part of the form So I want to make sure that those things Are validated in my test Because we so we did a Assertion on the part that did the right now. Let's do an assertion on the part that did the read So we asserted that we did the read What we Have configured this fake form to do is that whenever it's asked for the first name. It's always going to return this fixed string So now we should have a Passing test that covers one test case One test scenario for this existing production code there's Another the other test case that's in here. Can anybody tell me what that is? See if you're asleep. Come on. It's easy. There's only two things that can happen, right? The button is either enabled or disabled So what's the other test case is when we're going to say? Okay disabled when first name empty so we can it's very similar to this case so we can start out with this So let's see we know that The okay enabled set should have happened just like before except this time the last value should have been false Instead of true and we know that we should have gotten the value at the first name text So let's go ahead and compile this The build succeeded we'll go ahead and run the tests Okay, that one fails Now it fails because on my fake form it always returns Richard whenever I ask for the first name So what I need to do is enhance my fake a little bit so that I can say don't just return the same thing every time but I want you to On this test So this is the okay enabled when the first name not empty So I want to say form your first name text fake result Get fake result is Richard Yeah, I don't have that on my fake yet. So we'll go off and put that over there and the setter is going to say First name text get fake result value Go ahead and make a backing store for that And come back down here instead of returning this fixed string We will return first name text get fake result Now I've added that configuration here Does anybody think this second test that I've written is going to pass now? He says my code's not going to compile, but I don't need a getter on that Okay, now do you think my test is going to pass he says yes. He says no My test does not pass because that backing field was not initialized And I'm take trying to access the length property of an empty or of not an empty string, but of a null Value so we'll go back over here to our test and we say yeah, you know now I'm being really explicit about the state of this form before I try to exercise Production code that interacts with the form now. I'm saying You know in this case I said hey the name has to be empty for this test Well, that's what I said right here as I said the first name text get fake result is an empty string So now when I compile this go back over here now rerun my tests and What did I do wrong? Ah? I did not change my assertion because I copy pasted the What did I do here? It should have been set to all you have set to okay enable set call You mean in the implementation of this yeah, you're right look see kind of bug in my face Sometimes Automatic completion is a blessing and sometimes it's a curse Okay, now our tests are great. So we've covered The two Simplistic, but we've covered all the two different possible behaviors of that dialogue So are there Any questions on this before we go and add some new behavior to this dialogue by putting wiring it up through the mediator? Earlier versions of this presentation. I had a lot more behavior on the dialogue And we just found it was just too much work to get through in the in the time available So let's say let's go back and look at our Design view of this address form here, and we're saying hey, you know It's it's nice that this okay button is disabled when the required first name text is missing But it's an extremely subtle hint to the user So what we'd really like to do also is we'd like to enhance this dialogue so that the fields that require input are labeled with Red text and not just ordinary text So that's what we're going to go and try and implement test-driven style So we've covered all the existing behavior of this production dialogue with our existing tests and We're going to add some new behavior here Does anybody see some? Duplication here that we might be able to get rid of between these two tests. Okay, so Looks like we do this thing And we do this thing Every time in both these tests so while we're green we can take advantage of this time We also do it up here, although we pass in a null for this for the form So we've got some duplication between all three of these tests we can while we're green we can refactor that out into a Setup method Or what I'm going to do is I'm going to say yeah split that Declaration so I can take the declaration and put it up here and make it a member And let's do the same for this one And take that out put it up here and make it a member and then We're know we're going to need one of these forms let's move that to the common setup We know we're going to need One of these mediators put that in the common setup The mediators taking a form So I've moved that out of one of my tests I'm just leaving the other tests alone for now My build succeeded run my tests again. We're all still green. So that's good I didn't break any of my tests by this change now what I can do is I can say I Don't need to create this mediator here because It's going to make one in the common test setup and from my third test case I can say yeah, I don't need to make a form and I don't need to make a mediator Those are happening in my common test setup my build succeeded go back here run my tests again My tests are all green now if I was using a source code control system That would be a great time to commit changes and lock in positive games, right? So now we eliminated some duplication by just doing a little refactoring phase on our test code Let's go write the test for our new situation. We want to say Now when I first make When I first construct this form The first name field is empty. So as soon as I make the mediator Which is created at the same time as the form is created he should immediately say What's the first name text? Oh, it's empty your label should be read so I Was thinking I might need a new test case But it turns out because it happens as soon as the mediator is constructed because it's tied to the lifetime of the form I Could just add more assertions that say when you construct one of these This is something that should happen every time it's constructed because it's Lifetime and the form's lifetime are intimately tied together. So I can say on here It is true that on my fake form you should have Set the color of the first name label It's also true that The color it's set it to should have been read. I'm gonna need to add system dot drawing so I can talk about colors First name label color set last value Okay, I don't my fake doesn't know anything about these yet Let's go ahead and stub those out on my fake. I know what it's gonna look like Now some people Say, hey, it's just a fake object. I don't need to do that in encapsulation behind a property I'll just make the field directly on the fake We could do we'll just do one that way Yes, it's a system dot drawing color. So in that case, I just made it a public field on my fake I like to do the encapsulation with resharper. It's not significantly longer, but you can do it either way So, hey, that's fine. That's what our test says, right? Should these things should have happened Code built. Okay. Let's see what happens now Well now our construct test is failing because we haven't done anything on the production side to make this actually happen yet now What I've done is I've said, yeah, I need to know these things about my fake form But I haven't defined anything yet on the interface for the form that the mediator is going to use and then when we try to Go and make this Pass by adding an implementation over here. That's when we're going to find out Yeah, um, hey on the form the If the first name text length is greater than zero Then I don't need to do anything if it's Equal to zero. I want to say form that first name label color is color dot red And I want to use system drawing that color now he's saying yeah, but I'm only talking to the form through the interface The interface doesn't have anything that lets me set the color yet. So go ahead and put that over on the interface Because I've changed the interface The fake form and the production form now need to be updated to implement the new member So if I go over here to the fake form first I'd say implement the member Yeah, we strictly speaking we can go back here. We don't need to get on this. We can just do a set So then he says You're trying to set my color Let me remember that Last value Remember that too. Okay, so that's my fake and Remember we have two objects implementing the same interface and we just added a new member on the interface So we have to go back to all the objects that implement that interface and on the form We have to implement that now Over here. We haven't really implemented anything yet. I'm just going to leave that as Not implemented exception for right now Because you just want to test the behavior on our mediator first Okay, now everything's red So what happened? what happened was that on our fake form if I think this is what happened take a look at our test our test said We should have set the first name label color and That it should have been set to red So look at the mediator. He says We should have gotten the first name text and that we should have Set the label color if the text length was empty so Down here I have object not set to an Instance since I managed to confuse myself. Let's just go back here But it happened on all three tests So it must be this part that's causing the problem. That's the last change. We made Go back over here run our tests again. Our construct test is still red So my form must be No For my first name text must be no on my form Which it is on my fake So We changed the behavior Let's go back every look at our test. We changed the behavior of what happens when we construct a mediator, but Right here the mediator gets constructed the form was created But the fake form didn't have his first name text fake results set up to anything So what happened was that was null and then the constructor immediately tried to access that That caused our test to fail So now we'll go back here and look at this Okay, now our test is passing Okay, now we've made we've put the behavior over on the mediator We've made new behavior on the mediator But the last thing that we were missing was this Production implementation of our interface Now due to the way that we Put things on the interface. We said, oh, it's the okay enabled property. So I'm pretty sure that means okay button got enabled That's the production implementation of the interface Over here on this getter That's the implementation of that and This is first I have to go briefly over here to my designer and implement or generate a member for this label so we can talk to it through code So I had generate members at the false I change that to true So now I can say first name label that for color is Value Okay, now we don't have tests Directly covering this class this production code, right? We put all the behavior on another class and that's what we're unit testing so Making sure that you've got this stuff wired up properly Still requires manual testing But When we look at the code We just look at that and we say yeah, that's just correct by inspection. There's no branching There's no looping. There's no checking. There's no nothing. It's just yeah Take that thing and shove it on there or take this thing from here and give it back So when we look at this implementation of the production interface We say yeah, I can look at that and I don't feel that that's where the bug is as long as there's no Not implemented crap right as long as we implemented the whole interface Because these properties were really simple. They're just bully in the string. I just look at that and I think yeah That that's good. So now I Have my unit tests on my that covered my new behavior that I wanted to add now Let's just go and make sure that it's really on the form. Okay, so here's our main window And when I click out over here the labels red. It's red Because I didn't type anything Now it's red when it's it's set to red in the constructor. We covered one case But we still have more behavior that we would want to cover because we want to say yeah It shouldn't be red anymore as soon as I satisfy the constraint, right? So if we have time I Can go ready to test to that? We have time Well, it should take a few minutes Let's try it. Let's see how long it's going to take us to do that so back over here Go back down to our test and we want to say Well, we can enhance our existing test. That's just right any test We could have enhanced an existing test we can say The first name label not red when not empty I'm not really saying what color it should be. I'm just saying it's not red So I'm gonna say form That first name that fake result So it's not empty And say that you know that should have trigged whenever the the text has changed It should fire the first name text changed event and then we're gonna say assert that is true that on the form First name label color set was called and it shouldn't have been red. Okay, that's my test build Run my tests. My test is red. Let's go and make it pass Go back over here to my mediator and I'll say Yeah, you know what? Let's just say we'll add a getter on the interface Add a member to remember this original color, whatever it was. We're not saying what the color should be We're just saying whatever it is originally and now I have to go back over here to my production form and implement the new getter So down here. I didn't have a getter before now. I need one. I'm not gonna take that. I'm just gonna say return first name Label dot for color and I need to put that on my fake my build succeeded Go back over here to my test Tested screen. That was pretty cool. I didn't think I could get it done in three minutes, but Yeah, I did a similar Version of this presentation to dotnet user group meeting and I was going to submit the More elaborate behavior plus test version to their site. So John we can put a link to that on the wiki when I have it uploaded on their site Or we can upload another copy on your site, too. Yeah, the link would be perfect Well, it'll be no there'll be no the application Yeah, it might take them a while to get it up on their site, but we'll see Which ever is faster, we'll get it to you Sorry, what what are those sites? The dotnet user group meeting has a user group has a site. You just Google for that I don't know what use is on your head on your handout We'll get you and You'll have to copy your all because I did not make enough copies I was just wondering what is their point where it's where you wouldn't want to use unit tests in place of someone like Using UI a user interface automation They're so not the framework or it takes advantage of the accessibility interface and and you pretty much much fast Which is your going to detect states of the buttons and the text box It doesn't suffer colors. It's lose there But the hidden subtext under your question is does Microsoft really understand unit testing and I have to come to conclusion not really well, but the reason I say that is because the I Believe the framework you're talking about works through like event recording and event playback and You can make tests that way the problem is as soon as you go and change your UI all the tests break And they break for stupid reasons like you moved to control from the left to the right and now the mouse click at that XY position I don't think it deals with the XY location of the button as much as just the physical button It's also if the name of the button changes it breaks, but not so much location change Okay, but that's that's another good example of a fragile test, right? Why should I look at you would change but if I but see if I rename Using a renaming tool. It's gonna rename all the names in my in my tests, too I mean I could go right in here with resharp or do rename on one of those things members of the interface and a Rename it in my production code and in all my tests, and it would just recompile and still work Whereas if I I mean if I In this code if I go into the forms designer, and I change the name of a control as Long as the name of the control the rename gets reflected in that event handler and in the implementation of the interface Nothing else needs to care that my control name changed I mean, I'm not familiar with that framework, but I might as day that's Codeplex it has a whole testing suite kind of built around it But you can build the test suite right in right in as a separate projects You might be able to take take advantage of those renames as well. Yeah, I'd have to I'd have to look more closely at that one, but Generally event everyone ever says, yeah, I can unit test gooey stuff by doing event recording and then play back I've seen that I've seen people go down that path many many times On the other end of the forest they come out battered and bloody and bruised They never come out waving a flag going. Yeah, they all go that sucked I never want to do that again, and that's how they get to the conclusion. You can unit test gooey okay, so As far as that specific framework goes I'd have to look more closely into it But I would not recommend trying to do unit testing gooey By doing event recording an event playback unless the gooey is stable like it's you know We're just trying to get regression tests on this code, and we're not going to change this gooey And it's been the same for five years Then it's okay Because you're not changing it, but as soon as you change it all the event playback stuff breaks any other any other questions Okay, so we've had a chance We've had a chance to code on at each one of your table You know the person who was getting done fast So that is your driver So look at your table look at the guy that was getting done fastest at your table make him the driver All right, and then I don't care who the other roles are you've got make sure you pick up those roles All right, the learning is going to come from the conversation that you have between Hot Rod Hindley and the arm okay the old man and young that's where your learning is going to come We're about to do a little project, and I want it to go fast That's why I want the fastest coder at your table to take it So pick him who's your fastest coder point to him that table's only got two There's gonna somebody needs to go help that somebody needs to go be help that table Oh, they did with a pearl guy over there left So we need at least four there's there's two four We can send one more person back there to make to commentate with them, and that'll be good So fastest program right this table Who do we pick okay perfect who's doing this one here? Okay excellent, and then we're gonna have Doug if you want to be if you want to be the the baby That'd be perfect All right, so the exercise that we're gonna do Again a very simple one. We want a password validator now what a password validator in my goofy world means We accept a string and return return the input string if it is a valid password otherwise return null Okay, all right, so what I want to hear is I Want to hear I want to see the typing I want to see the pair And then I want to see somebody standing behind them talking to each other they get up behind him and talk Yeah, and talk and don't forget we're doing this test first so the comedy there just starts got to start talking who's the commentator Okay, so that makes you to the question tater. Yeah, so just talk talk talk and listen to those questions Yeah, play by play answer their questions try to maybe poke them Maybe they can be the color commentating occasionally You don't have a hot rod does it ignores boomer pretty much Okay, that's all the time you got We're shipping hands hands off the computer. We're shipping what we've got Yeah, this is arbitrary standard so So yeah would QA we don't have one of those We just laid them off if we don't get this release out right now We are companies going out of business and you guys should be working for free All right, so what are we shipping table table number one? What are we shipping? Do we isn't even working right now? Okay, so what do you got? All right, perfect. That's good. I like that table of you guys The first one so we're gonna ship Okay, how about you guys does it does it comply so it doesn't compile at all So it throws an exception is it gonna crash when they try to when they try to do the username and password or not We won't crash. That's good. That at least we won't get that Okay, everybody. Okay, so we can actually ship that Eight characters we got eight characters. How about you guys stop coding hands off the keyboard take it away. Thank you All right, so all right, so I've got I know All right, so that was our first that was our first release Now that you've got it out to customers. We are gonna do the next one A password recommender so what a password recommender is gonna be am I going the right way? Okay, so if the password is invalid return a suggestion and you got and You've got five minutes go So yeah, if you send a bad data Fail, but but it's trapped so the Let me let me answer that a little bit later because I want to stop this right now. Okay time That's it your time's up All right Hands off the keyboard over in that corner Okay, so We didn't quite get the exercise the refactoring exercise that I wanted to get to but we got the What I wanted to show you there is how many times did we have working code broken code working code? Is your code working right now? No, it's not if you hit controls the like three times would it be working? Yeah, see that that how about you guys is it working right now? Okay, how about that Okay, tell me what it so it compiles. Okay last time we had it last time I didn't let anybody through Okay, all right. How about this this team It compiles. Okay, and your team the what? It'll work. Okay. All right, so We had two tables We had two tables that actually were within three control Z to working back to working Okay, we could have actually shipped that we had a couple of tables that really we're going out of business Actually, we had three tables that were going out of business with and two that we actually stay in business with all right This is part of why I do test-giving development My code works within three or four undoes Okay, something can ship and something going to ship without bugs But you don't need a long extended QA cycle if you attended a case session she told my story and A year we ended up spent we locked the code down for two weeks and in that two weeks we did What are we doing that two weeks? Testing and performance testing and performance in the two weeks before we released The bugs just were fixed as we went we could have released three months earlier I mean the reason we landed on the date we said we would because we could have gone three months earlier just cut features We delivered features We delivered working features and we were within three control heat and if we're using source control We just pull the stack off the top and could hand it to them and that's going to work It's not going to bug in it. It might not have all the features It might have a half implemented feature, but it's not going to have bugs So two teams two teams survived out of and then three teams Who are the companies got out of business all right finally? I've got All right, who knows who this guy is nope Nope that guy is You know who that guy is Who's been to Wikipedia? Yeah, everybody that guy's Ward Cunningham. He invented the wiki Fitness he invented pair programming he invented all right. I tell you I have to tell you I have to tell you about that guy because he does not publish enough for himself He's not busy out promoting himself He's the guy that you sit down and talk to if you ever get a chance and he's brilliant You know who this guy is Somebody tell me that's Kent Beck He's the one that coined test-driven development. He's the one that wrote it up him and Ward Cunningham paired together All right, the reason I put this guy up there. That's Michael feathers He wrote legacy code You really he really can if you read the legacy code book some of the stuff Richard showed you How to do if you've got legacy code get his book learn those patterns Because if you want to do test-driven development you need to turn your legacy code into tested code And he tells you how to working effectively with legacy code the name of the book All right You guys know who that is That is Bob Martin Martin, Uncle Bob Martin He's the one that we did the first caught it. He did that caught of the prime factors and Solid clean code. He's got the book clean code. He's got the solid principles. He's worth reading All right, I've got one more thing so the name of this thing was try test-driven development and You in this class in a really short amount of time you've gone through multiple cycles of this All right, my goal for you is when you leave here you try test-driven development again and again And you can do it You've seen it I've shown you I've shown you I mean rich what Richard what Richard showed you Is some of the tough stuff What You know what when we went through the rhythm it's some of it's easy and some of it's harder There are some things you need to learn. That's on the sheet of paper if we got those out There's not enough copies There is not enough copies for everybody So you're gonna have to fight over them and at the bottom I'm giving one for cable at the bottom of At the bottom of the is a URL and that's been updated since I printed this copy out So for C sharp it's more current. So you need to go to the URL anyway, so I would write it down I am yeah, so I got more copies Okay, the one got another one the the thing you want is the really the URL on the bottom You've been absolutely fantastic class It's And I've got one more It was really fun. I've never I have not given Richard that three minutes So I really appreciate Richard doing that thing and we and as much pressure as we put on Jeff During his code that was really cool and then your experience. I mean it was it was amazing I did this for the C sharp music group and It just like was it took an hour to get through that at first exercise We managed to cut this one way down so you guys were awesome All right. Good luck