Lesson 5 of 5

Extract And Override With Validation Logic

Duration: 43:35 Watch on YouTube (external link, opens in new tab)

Markdown version

In this video Roy uses Extract and Override (external link, opens in new tab) with a complicated piece of validation logic, showing how you can set easy flags for unit testing (external link, opens in new tab) and recreating complicated validation scenarios.

In this lesson

Roy Osherove explains how to test validation code that combines many rules, using a password validator, by testing each rule separately from the logic that combines them. He introduces extract and override (external link, opens in new tab), also called the test specific subclass pattern (external link, opens in new tab), with a testable subclass that overrides the current time (external link, opens in new tab) so a check does not have to wait seven days. He then writes a validator test first, with flags in a testable subclass that set what each rule returns, and tests a single rule method directly (external link, opens in new tab) using the InternalsVisibleTo attribute (external link, opens in new tab).

Transcript

4,430 words

[00:04] (external link, opens in new tab) Hi everyone, my name is Roy Osherove and this is a short video that I'm doing about writing complex logic with complex business rules using test-driven development (external link, opens in new tab). The reason I'm doing this video is first of all so that I don't forget and second so that I can show it to students of mine during courses that I teach. And you can find out more about me by going to my blog at icerializable.com. And this is also going to be part of my book which is called the art of unit testing (external link, opens in new tab).

[00:36] (external link, opens in new tab) And this is an upcoming Manning publication which should be up in about I don't know 5 to 10 years. In any case, you will soon be able to download that book online through manning.com. And if you want to know more or get notifications or even just download the first chapter of the book right now, you can go to the.art ofunitesting.com and download that chapter and get notifications.

[01:08] (external link, opens in new tab) Now, the the the type of scenario that I'm speaking about right now is a very basic, you know, run-of-the-mill validation constraint logic type of scenario. It's the those kinds of scenarios where you have many rules and you have this big maybe function that checks all these rules and combines them and if depending on some convol logic it returns true or false or does something

[01:39] (external link, opens in new tab) And a lot of times this is part of validation process in many applications. So the the canonical example that I can think of is password validation function which returns true or false if something is valid or not. And there you know you can have a lot of rules for password validation. For example a minimum number of characters to have digits and so on and so on. Now of course you can use maybe some regular expressions to test these kinds of things.

[02:10] (external link, opens in new tab) But you know sometimes regular expressions are just for testing the test the text. What if your application needs to test something that is not patternbased? You want to make sure that this is done as well. So you want to make sure that all this logic works. So there are different challenges to testing this kind of function. First of all you need to understand that there are two kinds of tests that you need to to to write for this sort of logic. The first of all is that that you need to test the individual logical constraints.

[02:45] (external link, opens in new tab) For example, you want to know that if there are maximum number of characters that are exceeded, you want to know that something failed. So you probably would write a separate function and test it out that receives an input and returns true or false whether it passes or not. So you would probably write a different function for each rule and then there is the one layer above which is the logic that uses all these small constraints and combines them to give one single result.

[03:21] (external link, opens in new tab) So that's the logic that has all the if statements and it says well if there are maximum number of ch characters characters or there aren't any of these and this is not true then do something else. Now the main challenge is that once you know how to test these kinds of constraints is to write in test-driven development. So I'm going to show a demo of how you can actually write in a test-driven manner this kind of logic

[03:52] (external link, opens in new tab) Using tests that fail first. So here's an example of the validate function on a class and this is this is the hierarchy of how the validate function will work. This is how I want it to look or this is what I have in my mind when I think about it. So you'll notice that in the upper part here the validate function is merely using all these small functions underneath. Now each of one of these methods or functions

[04:25] (external link, opens in new tab) Is a rule on its own. It does a very simple thing and it has its own logic and this is the complex logic that I would like to test. However, I want to make sure that it's tested and I'm writing it in a test-driven manner. So if I spoke earlier about the two kinds of tests, you'll note that I basically will I'm going to write a test or many tests for the validate function and its logic, but I'm going to write separate tests for the has at least six characters and so on and so on.

[05:00] (external link, opens in new tab) And the tests here are going to pass or fail independently of the tests here. So even if has at least six characters its tests are going to fail the validate function its own tests might still pass because the logic here still works. So this is basically not very much different than separating dependencies in a regular TDD application TD written application just imagine that this is actually a web service call.

[05:36] (external link, opens in new tab) So even if the web service doesn't work, I still want to make sure that my interaction with the web service here still works. So this should pass even if this fails. And how do I do this? Well, usually the what happens is that the pattern in the code has to look similar to this. The code uses all these functions and the functions returns true or false.

[06:06] (external link, opens in new tab) And combining these values use during the test and telling those functions what to return can actually make us test validate separately. So here's an example. We are going to write a test that uses validate but it sets up the the the sub methods here to return the values that the test would like to return. So in our test the scenario would be if the password does not have a digit inside it that is this method returns false

[06:43] (external link, opens in new tab) And even though all these other methods return true the valid the validate method will return false to the test. Now, this is interesting because if you write test-driven development, you might not actually have this method or this method or this method. You might just have this method to test on, but you still want to make sure that in the next tests, the previous test is still going to to pass. So this will probably make more sense once we get into the code

[07:19] (external link, opens in new tab) But we are going to go through this scenario and use test-driven de development to write it. Now to understand that we need to understand a a very powerful technique that we're going to use during our testing so that we can actually control these values. I mean there has to be some way to control these values to that our test says well this will return true and this will return false and why do I want to control these values from my test I mean why should my test just give an input to validate that passes this but does not pass this

[07:56] (external link, opens in new tab) Well the answer is that sometimes to the input to validate by the end of the production code is going to be very very complicated. Just imagine that some of the requirements here may be very very powerful such as the inputs have to be defined in a certain way have to be of a certain size and so on and so on. So I would want to control them even though I don't want to actually run this code. I just want to simulate the fact that has digit returns false.

[08:28] (external link, opens in new tab) So my test needs to simulate that. And to do that, our test is going to have to create a class that inherits from the class that contains all of this. So if I'm going to actually use some drawing tools here.

[09:18] (external link, opens in new tab) So the technique is called extract and overwrite. If you're interested in learning more, there's a great book called working effectively with legacy code (external link, opens in new tab) by Michael Feathers (external link, opens in new tab) and there he explains this, but this is also called the test specific subclass pattern (external link, opens in new tab) if you read the Xunit test patterns book which just came out. So the technique basically says that we're going to create a subclass of the class under test and then overwrite each of these functions

[09:51] (external link, opens in new tab) And return whatever values we want. So let's see a demo of that and then continue. So, we're in Visual Studio and I just want to show you picture of my son It was born December 28th 2006 and I love him very much. So now he's in the video. In any case, here's my code for the book The Unit Testing and this is everything I have right now.

[10:25] (external link, opens in new tab) And I'm going to use this solution to show the idea of extraction override and the test specific subclass. So let's add a class that is depending on time so that we can test it and see how we can test it. Let's call it my timebased class. Okay. I'm going to also use a a program called Keyboard Jedi.

[10:55] (external link, opens in new tab) And the idea about Keyboard Jedi is that it will show any keyboard shortcuts that I'm using inside Visual Studio. I'm also going to use ReSharper so that if you see me doing something like this, you can see that I clicked alt plus enter to show the menu that you're seeing right now. So, this is part of Sharper. I'm just going to optimize the using here. Let's do a public class.

[11:26] (external link, opens in new tab) And I'm going to write one simple method called public string get current time (external link, opens in new tab) to see that it's actually get current time. And well, let's just say that my method is going to be like this.

[12:02] (external link, opens in new tab) So the method I want to write is a method that maybe is used for backup. And so the method should tell me if a week has passed since the last backup. So let's write a property let's write a field let's say date time. Now the daytime is we're going to use system daytime to say

[12:33] (external link, opens in new tab) Last backup. And let's create a property. That's the last backup. And let's also do something like public should

[13:03] (external link, opens in new tab) Back up. Now, let's return false. Well, let's return daytime sub. Let's datetime dot now subtract last backup is

[13:35] (external link, opens in new tab) In days is bigger than seven. So if more than seven days have passed since the last backup, it should return true. Now how can I test this method? So let's try to write a test for this method. Let's add a new class. Let's call it and since this class is called my timebased class, let's call it my timebased

[14:06] (external link, opens in new tab) Class tests. Now this is a test class. So it's going to be public and test fixture and let's write a test here. Now in my test I'm going to write three parts. The first part is going to be the method that I'm testing. So should back up now is the name of the

[14:38] (external link, opens in new tab) Scenario is less than 7 days away returns false is what I'm expecting. Okay. So, how can I test this? So, the first thing I'm going to do is I'm going to refactor the class because I don't want my test to have to wait seven days. So I'm going to actually write a new class here called testable my

[15:11] (external link, opens in new tab) Timebased class which inherits from my timebased class. Now the reason I'm doing this is so that I can overwrite some stuff. But what do I override first? I'm going to get the current date time and convert that into a method call. So get time now and let's make it

[15:42] (external link, opens in new tab) Protected and make it virtual. That way we can overwrite that in the class in the testable class. So, what I'm going to do now, I'm just going to override my get time now and say return current time. And what's current time?

[16:13] (external link, opens in new tab) It's going to be a field called current time. Let's make it public. What else? So now I can use my actual testable timebased class. Testable timebased class backup equals new testable timebased class. Now I'm going to tell backup that the current time

[16:44] (external link, opens in new tab) Equals new date time. The year is 2000. The month is one. The day is one. That's okay. Now the thing is since this overrides the behavior and actually in the X test patterns book this is a variation of the pattern. It's called

[17:14] (external link, opens in new tab) Behavior modifying subclass which is pretty smart. What we're going to do is in the test we just told it what the time is. And now we're going to say backup should back up now.

[18:03] (external link, opens in new tab) Result or let's call it shoot backup now. And I'm going to assert is true on the backup now. So let's see. Here is a test that should actually say well okay this is wrong because my test actually says has to be less than seven days. So has to be is false and the new date time is

[18:43] (external link, opens in new tab) Okay. Okay. So we have to tell the backup here backup backup last backup equals new date time and let's say 20 1 and 1 and the current time will be 200 and five. So backup now should actually return false.

[19:15] (external link, opens in new tab) Okay. So current last backup is a standard property. So you can see that in the production code we would actually be using the real date time. But in the tests, we're actually getting getting the the the time that is under the control of our test. So this is called behavior modifying subclass.

[19:47] (external link, opens in new tab) By overwriting the method, I just change the behavior of the class under test. Therefore, I can override time. I can make time stand still and my test will always run. Let's write the opposite test and see that it actually works. Should back up now more in seven days array returns true.

[20:19] (external link, opens in new tab) So let's say eight or actually nine. This should be as true. Let's run all of these. And this is actually an addin called testdriven.net that I'm I'm using and I'm running it here. See, two tests have passed. And that's it for now. Let's go back and actually see how we can use this technique

[20:51] (external link, opens in new tab) To catch complex validation logic. So that was the demo. Let's take a look at what we're going to do now that we know about extract and override (external link, opens in new tab). So, we're going to write a password validator class that has all these complex rules and we're going to write a test that uses a validate and it's going to have various virtual methods that we're going to use and we're going to actually override these virtual methods in our test and do in a test-driven manner.

[21:26] (external link, opens in new tab) So let's see what that looks like right now. So let's write our validator from scratch. So I'm going to actually write a class called validator. But my first test is actually going to be on a method called is valid that takes a password. Now I'm actually testing it on the logical level the one that uses the rules.

[22:00] (external link, opens in new tab) I'm not testing the actual rules right now. just the fact that the rules are being used correctly in the first and that means that I'm checking checking is valid when rule which is called at least six characters is false then it should return false that means all the other rules return through.

[22:34] (external link, opens in new tab) So what am I what am I starting with? I'm going to start with the actual testable validator class. Testable validator TV equals new testable validator. And I'm going to make it compile soon, but let's finish the test first. TV. And I'm going to say set all flags to true.

[23:12] (external link, opens in new tab) Which is my way of saying I'm only testing one rule right now. You'll see that it's a very simple concept. Next, I'm going to say tv flag at least six characters is actually false. So that rules that rule is not passing. All the other ones are. And the next thing I'm going to do, I'm going to say bull is valid equals TV is valid.

[23:46] (external link, opens in new tab) Some meaningless text as password. Now, this is actually meaningless text as password because I'm not actually testing that it's using the string here. I'm testing that it's calling the underlying rules. The string right now is meaningless.

[24:16] (external link, opens in new tab) Me some meaningless and I'm asserting that something is false and that would be is valid method. So I'm pretty sure that when you're looking at test right now this seems very very weird to you because there is nothing here that makes much sense but this is the way we are testing the the logic this the way we generate in test driven manner. A testable validator is a validator that allows us to muck around with the behavior.

[24:47] (external link, opens in new tab) And what are we doing with the behavior? We're saying, well, all rules are going to pass internally besides this rule. Now, when that's true, when all this is true, but this is false, the is valid should actually return false. So, let's make this happen. Let's generate the testable validator class and that's actually going to inherit from a validator class which is not existing right now.

[25:19] (external link, opens in new tab) So let's create a class and this class is going to be our production code. So this is our test specific subclass and this is the class that we're actually testing. Now let's turn our attention to this interesting method which right now does not do anything. So let's create a field

[25:50] (external link, opens in new tab) Called flag list characters. And now this method will actually set all the flags. Right now we only have one flag at least six characters is actually actually true. Whenever we add more fields like this, we're going to add a a row here that sets that flag to true. And you can definitely write a simple reflection related method that

[26:22] (external link, opens in new tab) That loops through all the fields and whatever starts with flag it sets to true. Now the only thing left is to actually implement the is valid method and the is valid method is actually going to be generated on the testable validator class. We are going to move it quickly into

[26:55] (external link, opens in new tab) A see I'm going to refactor it quickly and say that we're going to move it up into the base class. So this is valid here. So now is valid is part of the validator class and obviously it throws an exception. Now where does this flag take place?

[27:25] (external link, opens in new tab) Well to do that we need to implement the business rule here. So I know I'm going to do a test driven and the way I'm going to do it is going to say override and I'm going to override a method that doesn't exist yet. And that method is going to be has at least six characters that takes a password string

[28:09] (external link, opens in new tab) Now the interesting thing is is that I'm going to create the method in the base class and it's going to be generated as a private virtual method.

[28:41] (external link, opens in new tab) Now what we're going to do is actually say return flag at least six characters. So what do we have so far? We generated a production class that has an isalid method and has an at least six characters method and they both throw an exception. Now we're going to write a test for this one separately. Right now we're testing this method and our test is going to prove that this method is not calling this one.

[29:13] (external link, opens in new tab) How do we know? Because we are actually testing this class which inherits from this one. And in this class we override the has at least characters method and say that this one returns false. And if this one returns false, then in the production code, this one should not throw an exception. It should just return false. I hope that makes sense. Let's run the test and see what happens.

[29:48] (external link, opens in new tab) And obviously I get an exception. The method operation is not implemented. So let's make the code pass as as simply as possible. And to do that, let's just say return false. Now, if I run on the test, obviously it will pass, which is weird. So, let's do another test. I'm going to duplicate this code and say, well, is valid when rule is actually true?

[30:27] (external link, opens in new tab) So this one is actually true and obviously my test will fail. Expected true but was false. I can see here this is why it failed. So let's make the code actually use the production method here.

[30:58] (external link, opens in new tab) So return has at least six characters. No. Why does that matter? Well, this is a problem. We're going need to need to prove that I'm actually going to have to send in the actual password. But as you can see, the two tests are now passing. So, let's add another rule. Things should get pretty simple from here. The first rule I'm going to add is to say

[31:36] (external link, opens in new tab) Test is valid. has no spaces is false returns false. So testable. You know what? Let's just make this into a setup method (external link, opens in new tab).

[32:14] (external link, opens in new tab) We're sharper, refactor, and convert. Oh, never mind that. Let's public setup

[32:49] (external link, opens in new tab) And I just say this here I'll do TV and now let's use this TV set all rules to pass. Now TV flag has

[33:20] (external link, opens in new tab) No spaces equals false, right? And TV is valid. No, doesn't really matter. on valid. So when flag has no spaces false, the TV should turn the testable

[33:50] (external link, opens in new tab) Validator should turn false. So let's generate this field and flag has no spaces is also true here. And I'm going to override another method. Override bull has no spaces. Return flag has no spaces. Let's generate this method. Create method and base class.

[34:23] (external link, opens in new tab) Let's run all the tests. Bam. Expected false but was true. Interesting. So what does that mean? Means that all we have to do is add this call here and If you run the test right now, they should all pass.

[34:57] (external link, opens in new tab) So what happens if we want to test a rule that says one is true and the other is false Well, we obviously don't need to test the other rule the says when this is true because we already have something that says test when everything is true and everything passes. So now what we want to do let's say that we need to add another rule and this one is going to be

[35:30] (external link, opens in new tab) As valid when rule let's say has the letter A is false has no spaces is

[36:01] (external link, opens in new tab) False then it should return true. Why? I don't know why. That's just that's that's just a rule that I just made up. So it if it doesn't have the letter A, but it also doesn't have any spaces, it's okay. So let's see.

[36:32] (external link, opens in new tab) This one is good. Then flag has the letter A is false. Then valid should be true. Let's create a field here. and flag has letter A is true here. Now let's override something else

[37:22] (external link, opens in new tab) A. Let's implement this. Done. Notice nothing here happens. Now I need to add this test here. I'm running the tests. Obviously this test fails. So now I need to add my new logic here. So the logic that I need to add should be here.

[38:25] (external link, opens in new tab) So if it has a space but it it h it doesn't have the letter A, it should return true. Return true. I hope I did that right because now it's starting to confuse. Let's see by running the tests. Bam. And they all pass, which is interesting. So now even if I change this to from true to false all my tests should pass even though the logic is horribly flawed.

[38:57] (external link, opens in new tab) I mean it's not flawed. I mean implementation is not there. Now I can actually let another team write the implementation here. For example some special algorithms team. So let's try to write a test for the method here have at least six characters. And how do I do that? Well, how do I get access to this? Well, I can actually inherit in my class from testable validator.

[39:30] (external link, opens in new tab) Another thing that I can do is I can actually use the attribute of friend attribute. What was the name of that? Internals visible to attribute. So I can actually say internals visible to attribute as a type of assembly attribute here and just put in the name of an assembly. And if that assembly is a test assembly,

[40:04] (external link, opens in new tab) It can still look at the protect members or the internal members, I'm sorry. Now, the last thing that I want to do, I'm actually going to move the validator to another file I can actually start testing stuff here. So let's add a test. Now notice the name of the difference in the name. The the difference is has no spaces.

[40:36] (external link, opens in new tab) That's the method I'm testing. That's the difference. Has a space returns false. So string password equals space. Okay? Because that's the simplest thing (external link, opens in new tab) I can think of. Validator V equals new validator V.

[41:07] (external link, opens in new tab) This interesting how do I get access to that? Well, I should say internals visible too. So, I'm actually going to go to V here and say protected internal protected internal and I'm going to say V and you can see that I can see here now here

[41:39] (external link, opens in new tab) Now if this was a different assembly all I had to do is to put that internals visible too and put the name of my test assembly in there and I would get the same list as it looks has no spaces let's give it the password let's get the result is false has no spaces. If I run my test,

[42:26] (external link, opens in new tab) Sorry. And of course, this is methane. Let's run my tests again. And of course, my test has failed. And it's failed because has no spaces throws an exception. So all I have to do is say return password contains space. Obviously this could have been much more interesting if the algorithm was more interesting.

[43:01] (external link, opens in new tab) Bam. All the tests passed. So that way I'm testing the actual algorithms and the logic that uses them separately. Now, by now you should probably be aware that there is it can get more complicated than that. But these are the basic steps that you can do to get this thing rolling. So, thank you for your time.

[43:31] (external link, opens in new tab) I hope you stop by and check out my book. Thank you very much.