Lesson 5 of 14

Isolation Frameworks

Duration: 1:01:27 Watch on YouTube (external link, opens in new tab)

Markdown version

Roy reviews the basic differences between the various isolation (ocking) frameworks (external link, opens in new tab). Also explained is the difference between profiler based (external link, opens in new tab) and proxy based (external link, opens in new tab) frameworks.

In this lesson

Roy Osherove explains isolation frameworks (external link, opens in new tab), which create fakes (external link, opens in new tab) at runtime, and divides the .NET ones into proxy-based frameworks (external link, opens in new tab) such as Rhino Mocks (external link, opens in new tab), Moq (external link, opens in new tab) and FakeItEasy (external link, opens in new tab) and profiler-based ones (external link, opens in new tab) such as Typemock Isolator (external link, opens in new tab), JustMock (external link, opens in new tab) and Moles. Profiler-based frameworks rewrite the IL at runtime through the CLR profiler API, so they can fake static and private methods; proxy-based ones need interfaces or virtual methods. He compares their APIs on the same logger tests, from string-based NUnit (external link, opens in new tab) Mocks to Rhino Mocks extension methods, and shows Isolator faking static methods (external link, opens in new tab) and future instances.

Transcript

8,711 words

[00:28] (external link, opens in new tab) Okay, everyone awake? So I want to continue the discussion about mock objects (external link, opens in new tab) and talk about some of the terminology to previews make it a bit more official and then we'll move on to isolation frameworks (external link, opens in new tab). we we reviewed the idea of mocks and stubs (external link, opens in new tab), but let's start with a a fake (external link, opens in new tab). A fake

[01:00] (external link, opens in new tab) Is anything that can replace anything else in the system based on how you use it. If you verify calls against it, it's a mock. Or if it can fail your test, it's a mock. Otherwise, it's a stub (external link, opens in new tab). Now, a stub cannot fail your test. A stub should not throw exception unless it's so you can test something else. There are there are other ways to there are other

[01:34] (external link, opens in new tab) Words to describe these things. There's a book called xUnit Test Patterns that talks about various different definitions of these fake objects and based on how much code is inside this thing whether it contains custom code or not they have a different take on the naming. So test spy double fake mock stub all mean different things within the same realm. I believe that this is too complicated. So that's why I use only three terms.

[02:06] (external link, opens in new tab) The term fake, term stud, and the term mock. Everything else is not important for our purposes. Yes, based on that xUnit patterns book, you can actually look at mocks and stubs and even and and tear them apart into even smaller definitions. But for what we need, it doesn't matter because the only reason I use the ideas of mocks and stubs is so that I can review and understand if a test is oversp specifying, has more specifications than it needs to, is testing more than a single thing.

[02:40] (external link, opens in new tab) And it doesn't really matter if that fake stop is halfwritten or fully automated or doesn't do anything or has a lot of logic inside it. Okay. With the manual fakes the way we've done it so far. What happens if the interface that we are creating a fake for has a lot of methods?

[03:13] (external link, opens in new tab) Okay. What happens if each method has a lot of parameters? It begins to be very complic not complicated but very time consuming and actually boring to recreate very large interfaces with a lot of parameters. What if we wanted to verify that something was called more than a single time and that each time it had different values? It's not complicated to save these values into an array of some sort and then verify but it begins to be just timeconuming and boring and not important.

[03:46] (external link, opens in new tab) So that's where isolation frameworks, a lot of people call them mocking frameworks. That's because the term mocking is overused. I call them isolation frameworks because you use them to isolate a unit from its dependencies. So these frameworks what they do is they allow us to save a lot of coding time by creating these fake classes for us so that we don't need to do anything but write a couple of lines of code to get an object that is fake and behaves in a specific way.

[04:29] (external link, opens in new tab) Now when we're talking about the these frameworks, what they do is they usually do this all dynamically at runtime. They also do all that basic stuff like saving values, saving the parameters and all that stuff for us. And they can also simulate exceptions and all the other things we want we would want them to do. So it's just imagine that you have written unit test for many years and every day you find yourself writing the same fake class with the same fake behavior over and over. If this is exception is being said then throw it.

[05:02] (external link, opens in new tab) If this is being saved then save the value, save it to an array blah blah blah. Eventually you're going to end up with some infrastructure for doing this this thing. And that's where isolation frameworks began as infrastructure. And then someone took them took that and made it even more generic. Now the this is a very important part. There are two big types of isolation frameworks and based on which type you choose you get very different abilities because they're built on very different technologies.

[05:35] (external link, opens in new tab) The way I look at isolation frameworks in .NET they're they're divided into two different types. There are profilerbased frameworks. There are proxy based (external link, opens in new tab) frameworks. No one tells you this, but the frameworks have very different abilities. And I'm going to explain exactly what profiler based (external link, opens in new tab) means. But first of all, let's look at the list here. Let's talk about proxy based because that's where most people are. Proxy based you're going to find all the familiar frameworks like Rhino Mocks (external link, opens in new tab), Moq (external link, opens in new tab), etc.

[06:06] (external link, opens in new tab) There's also NUnit Mocks which is a framework built into nunit with mock objects. No one uses it and no one should use it because it wasn't built to be used by the public. It was built to test NUnit itself. However, some people like to to to see the word mock and try to use it. We're actually going to see a demo of that to see why you shouldn't use it. And I've put these signs to to to tell you about frameworks that I wouldn't recommend using anymore. So I wouldn't recommend using NUnit Mocks and I wouldn't recommend using Rhino Mocks even though Rhino Mocks is actually in in the book that I wrote because with the time that I wrote it it was a good decision.

[06:46] (external link, opens in new tab) Now Rhino Mocks has become a bit overloaded with a lot of different APIs. It's much more difficult or complicated to use than the other frameworks here. These days I would recommend Moq or FakeItEasy (external link, opens in new tab). Some people really like NSubstitute. I don't have a problem with that. What's what's interesting is that all these frameworks are all either open source they're all open source and free. What's interesting about profilerbased frameworks is that none of them are open source

[07:20] (external link, opens in new tab) And most of them are not free. So Typemock Isolator (external link, opens in new tab) is not free, JustMock (external link, opens in new tab) is not free. Moles is free but it's was built by Microsoft and it's not open source. Now so I'm going to talk about what profilerbased frameworks are and then I'm going to explain the the the the differences between these and we're going to see an example of the API of most of these to see that they also have very different design decisions built into the API and the design decisions also affect the usability, readability (external link, opens in new tab) and maintainability (external link, opens in new tab) of the tests.

[07:56] (external link, opens in new tab) So profilerbased frameworks they use a technology called profiler API. This is an unmanaged wrapper running around the CLR. The CLR is a runtime COM-based runtime and you can actually host your own CLR in a process if you really wanted to. The profiler APIs are an unmanaged COM-based wrapper that you can actually register to them and receive interesting events about anything that's happening inside the CLR.

[08:35] (external link, opens in new tab) Now to enable the profiler APIs, you have to set up a couple of environment variables in the process that's running the CLR. That's all. Once you have these environment variables up, you you can actually register and receive a lot. I'm talking about hundreds of different events. Now these events give you a lot of power. An example is that you can get an event before or after each method gets called or executed.

[09:06] (external link, opens in new tab) Another important event is before module load. A lot of the frameworks, profiler based frameworks use this because they this event actually gives you the IL at runtime before it gets compiled into binary code in memory. So the way the CLR works is that when you write code, you compile it, what you get is not a binary that contains zeros and ones is you get binaries that contain IL in bytes.

[09:38] (external link, opens in new tab) And then the IL is loaded into the CLR at runtime and gets transformed into zeros and ones based on the current machine and CPU etc. So it's actually optimized for the machine it's running on. That's why sometimes people say that CLR based programs can actually run faster than C++based programs because when you compile to C++ you compile to the most lowest common denominator. you don't know what CPU you're going to run at. But here we know what CPU we're going to run at because we are on that CPU right now.

[10:11] (external link, opens in new tab) So we can use special flags etc at runtime. But because of that before we before the IL gets transformed we can actually get an event and we can change the IL the intermediate language before it gets compiled. Now the IL is all the program. We can get the source for all the program including the IL for all the third party programs as well.

[10:42] (external link, opens in new tab) So for example if I am writing if I'm loading a SharePoint based code not only my source code gets transformed into IL it gets the not only my IL gets transformed but the SharePoint IL gets loaded as well. So I can actually transform IL of thirdparty applications as well. So what a lot of these frameworks, the profiler based frameworks do is they not only give us API to to override and retrieve stuff, they actually transform the IL of all the methods or most of the methods that they would like to and they give us an API and and in all these methods they give us hooks that say basically is this method should this method behave as a fake method or not.

[11:29] (external link, opens in new tab) So that when the program is compiled, it's compiled that every method begins and ends with a question. Should I throw an exception? Is it fake? And all these gets get hooked into managed APIs that the frameworks give us. And so now imagine that you can use the frameworks to say whenever you have a method that begins with the the letter A, it has to throw an exception. We can actually do that. Whenever you have methods that have more than three arguments, they always return false.

[12:00] (external link, opens in new tab) So this is basically AOP which is the initials for aspectoriented programming. So profilerbased APIs give us the ability to do aspectoriented programming. It just happens to use AOP to fake specific behavior of methods and objects. Now because of that we can fake the behavior of any method we ever want. Static methods, private methods, static constructors, whatever you want cuz everything is IL really.

[12:32] (external link, opens in new tab) There is no prevention or limitation on the behavior you would want including for example the behavior of date time. You can say the daytime now always returns the year 2000 if you really wanted to. And in fact in most of these frameworks you can actually do that. You can say set date time now to be the year 2000. And that's so profilerbased frameworks are notoriously hard to write because they're they have unmanaged profiler APIs.

[13:05] (external link, opens in new tab) The profiler APIs have little or no documentation. It's as if they have security by offiscation, if you will. But the offiscation is not intentional. It's just neglected. And whoever gets this magic potion can create their own framework that can do basically anything. So now when we get back to profilerbased frameworks, what's interesting about these profilerbased frameworks like Typemock Isolator, JustMock and Moles is that they all allow you to fake whatever you want.

[13:40] (external link, opens in new tab) And that's very different from proxy based frameworks. And I'm going to explain what proxy based frameworks are in a second. But proxy based frameworks by default have much less abilities because they do not use the profiler based APIs. They cannot change the behavior of everything. They only change the behavior of things that you can inherit and override (external link, opens in new tab) just like we did in manual code. So in terms of profilerbased frameworks, Typemock Isolator is the oldest one. It ex it's it's been in existence for at least seven years I think or even eight.

[14:16] (external link, opens in new tab) And it's a very mature product. I used to work there. I worked there for about 3 years as CTO but it existed way before I joined. And I helped create one of the APIs that you will see. And I quit that place about a year ago because I wanted to find my some my my roots in different places. But it's it's an amazingly powerful product and it's been in use for a long time. So, it has been matured. It's been going through basically any scenario a customer would need and and mostly working for anything.

[14:52] (external link, opens in new tab) Now JustMock is a relatively new cover about two years maybe and JustMock has mo I would say probably 60% of the abilities that you can do with Typemock Isolator not not because it doesn't use the profiler based API it does it basically they both have the same potential to do anything but they expose different abilities okay to expose all the abilities in in a managed API in a usable way is very difficult.

[15:25] (external link, opens in new tab) So JustMock as a relatively new product has a lot of abilities but it keeps adding more and more abilities. It has not yet kept up with the abilities of isolator. It also costs about half of isolator. So as as as we're talking right now isolator is costing about $800 per seat which is a lot of money but in legacy code (external link, opens in new tab) situations it's amazingly useful when you cannot change code. You can fake whatever you want. Just cost about half of that.

[15:56] (external link, opens in new tab) And Moles is interesting. It's it's actually free and it's part of a tool called Pex which generates unit tests based on conditions it sees in your code. But I would not recommend using this framework at any cost because the API is not meant as an isolation framework. The API is meant only for faking things, not for verification. And it's a very unusable API. It's almost an afterthought. So if you use this API, what you get back is unmaintainable and unreadable tests.

[16:30] (external link, opens in new tab) So it looks cool at the beginning, but then it it it deteriorates very quickly. Also, the way you use it is that you point it at an assembly, then you generate two types of objects from it. There are stub objects and there are mole object. Stub objects basically work almost like proxy based or just like we did manually where we created something that inherits or implements an interface and then override all these things and then the mold objects are for all the things that you would use isolator JustMock for all the things that you cannot fake with proxy based statics etc and they these APIs look different that's very confusing and very annoying to learn

[17:14] (external link, opens in new tab) So I would I would recommend to stay away from it, but you have to know that it exists. So you can stay away from it. So it's not really free. It's just free by definition, but it's not free when you when you work with it. It actually cost you a lot of time. Time equals money. So let's move over to proxy based frameworks. Proxy based frameworks most of them depend basically on the idea of a proxy inside .NET. There's an ability to create classes which proxy other classes.

[17:46] (external link, opens in new tab) They look like them and they and you can actually generate code that looks like a specific interface or a class. But most of these take it one step further. They use a a framework called castle.proxy or Castle DynamicProxy. And this this library uses all that what I just said the proxy ideas in .NET. But the way it does it, it basically they all generate code that inherits

[18:16] (external link, opens in new tab) Or overrides code just like we did manually. So let's say that you had an ILogger interface (external link, opens in new tab). You can use e any of these proxy based frameworks to create a class that inherits from the ILogger interface override and saves the values and and whatever. But it happens in at runtime. You don't really get a new class in your code. Now you can do all these things with isolator and JustMock as well. It just doesn't happen the same way because because they use a profiler. So it looks like it's done the same way but in reality it will work on any method on that on that class.

[18:53] (external link, opens in new tab) So you don't have to have an interface to fake something with a profilerbased framework. You have to have an interface or a class with virtual methods that you can override with proxy based frameworks. So essentially anything that wouldn't compile if you had done it manually you cannot do with a proxy based framework because it does what you did manually does it automatically. Yes. Would you if you invest in a license for a profiler based framework would you only use it or would would you still use the the proxy based well because as far as I've seen the syntax might be a bit more accessible or something at times.

[19:31] (external link, opens in new tab) We had this question because we consider to get probably just because we have a Telerik license we could upgrade to that and the problem is so are we using two or one so what is what's your opinion on that >> well if you have a choice and you can use two frameworks or one framework I would go with one framework >> because in terms of learning you you want to have the same API throughout your test it's better >> so all the the profile will do both abilities so it's better to use one.

[20:01] (external link, opens in new tab) Now JustMock kind of has a two two modes. They have like a free mode that works like a proxy based framework and they have a non-free mode that works like a profilerbased framework. So it's it's kind of like you get JustMock but you don't really get the abilities of profiler based until you actually pay something. >> Okay. And Typemock used to have such a mode, but it doesn't have that anymore.

[20:31] (external link, opens in new tab) So, you you get it and you get everything included. Okay. So, what we're going to see, we're going to see examples of of nunit Rhino Mocks and FakeItEasy. And then we're going to see isolator. I don't have examples with Moles and JustMock because isolator is my specialty. Although I've used both of the other ones I think that I don't want to overburden you with too much information.

[21:04] (external link, opens in new tab) So and also again I don't have any agreements with any of the companies etc. It's all just my personal beliefs. Okay. So let's see a demo. So what we did so far is we we've seen manually how we can how we can actually

[21:36] (external link, opens in new tab) Create fake loggers manually. Let's look at NUnit Mocks and see why some people really like it even though they're not supposed to use it. So this is the the simplest the simplest elevation above from manual fakes as you can think of. Instead of creating a fake logger class, what I do is I add a reference to any mock dl and I create a class called dynamic mock

[22:06] (external link, opens in new tab) And instead of creating a class, I say new dynamic mock and I give it the type to implement. Then I tell the my dynamic mock to expect a call on a method called write with the value called yo. Notice that it's all string based and that's one of the big differences from all the other frameworks which are newer. They're not string based anymore. So string based is a problem in terms of refactoring.

[22:38] (external link, opens in new tab) If my method changes later it's a problem. So I say look I want you to expect write with yo now at the end I will just say mocklog.verify verify but where is the fake instance coming from I will say mocklogmach instance and I will cast it into ILogger okay so at runtime what's going to be what's going to happen is that it's going to generate in mock instance a class that actually inherits from ILogger implements all the methods saves all the values and does whatever it needs to do and it generates it at runtime compiles it in memory and gives gives us the the instance.

[23:18] (external link, opens in new tab) So it will actually match logger interface and that's pretty cool because it saves us some work. So this is the same class we use login manager with mock. We give it an ILogger which is the mock instance. The mock instance is going to behave based on how we told its parent how to behave to expect write yo with this value. Then we can say mocklog.verify verify and that will go through all the expectations. I can have multiple expectations on what could happen

[23:50] (external link, opens in new tab) And if one of them didn't happen, it's going to fail. Or if one of them happened with a different value, it's going to fail. I'm going to get an exception. Okay, here's the same example, but this time with two dependencies. Create a dynamic mock of ILogger and call it stub logger. create a dynamic mock of IWebService call it mock service these are two fake objects

[24:20] (external link, opens in new tab) Okay but it's called dynamic mock because the idea of fakes versus stuff is not in the API so the name of the variable that I use is now very important because that's the only way to tell that that that's how I intend to use the object now if I wanted to simulate an exception I will tell the stublog expect and throw on method Right? Always throw a logger exception. Okay? When you get yo

[24:51] (external link, opens in new tab) On mock service, I say just expect write and got exception. Now notice that I'm I'm only doing at the end I'm only doing one verify. I'm not doing two because one of them is a stub. I'm not going to verify against it. I don't want to assert that it got called. I'm only going to assert that the mock service got called. The stub logger is going to throw something, but I'm not going to verify that it got called. Okay? Because I don't care if it got called.

[25:21] (external link, opens in new tab) I just care that it simulated something. So, if it didn't get called tomorrow and everything still worked just the same, my test will not break because what I care about is just the end result (external link, opens in new tab), which is this. Okay? So we have a stub logger expect and throw expect here and then we initialize login manager with mock and stub with an ILogger of the stub logger and an i web service of the mock service.

[25:54] (external link, opens in new tab) Both of them we get the mock instance here. And you can see the tool tip says it returns object but at runtime that object can be cast into the specific interfaces. Okay. Any questions so far? Okay. So are there any benefits or pros or cons that you can see with this API? >> Anything you like about it? >> No. >> You don't like anything about it? I must admit yeah well the one thing I instantly see is this the problem with the string that you mentioned and the other thing is that in the verify I don't see what I'm verifying because it's in the expectation.

[26:40] (external link, opens in new tab) >> So you don't see what you verify at the end because it actually happens in the beginning the the expectation and the fact that it uses strings so the refactoring might be a problem later. >> Yes. >> Okay. I agree. But I also want you to notice that there is a design decision here that we have basically two things that we interact with. We have the the dynamic mock object which is basically the parent. That's the thing that you set all the expectations on.

[27:11] (external link, opens in new tab) And then you have the actual fake object which is from mock instance. So we have a parent and the actual fake. And there are two separate objects. And that's a design decision. Okay. And the reason I'm I'm telling you to focus on this because we're going to see different designs very soon and they're not going to look anything like that. Some of them will, some of them won't. Okay. So, that was NUnit Mocks. And again, this is not recommended to be used. This is just an example to show the history of how frameworks have basically evolved since then.

[27:47] (external link, opens in new tab) Okay. And I agree that the fact that the expectations are here, the verification is here, it's kind of hard to read. Okay, let's look at Rhino Mocks. This is how you would write the same test with Rhino Mocks. So let's go through this. To create an ILogger, let's make this like this. We basically call a static class called mock repository and we say generate mock.

[28:21] (external link, opens in new tab) It also has a generate stub method. Now this time the method is generic. So it doesn't return object and what we get back is directly the fake object of the type. There is no parent that we set the expectations on. Okay. And then we say okay initialize login manager with the mock and send it the mock logger. And now suddenly we have a method on that ILogger interface called assert was called given the logger

[28:54] (external link, opens in new tab) Which is the fake logger. Did something like this happen to that fake logger? So the refriation is at the end and where did assert was called come from? That's an extension method. Okay. So what we see here is that actually arrange act and assert behave like we used to do before. So in terms of readability it's definitely nicer. Now assert was called is an extension method.

[29:26] (external link, opens in new tab) It means that there is there are extension methods on the type of object in this API. And that's both good and bad. It's good because now you can go to the fake object directly and say assert that you were called and it will fail if it wasn't. But it's also a problem because in terms of API if I go and I say something

[29:57] (external link, opens in new tab) So something and I say dot I can actually do a search was called on something that's not even fake. And that's a problem. It's actually confusing. I don't want to I don't want my IDE to tell me that I can do things that I shouldn't and in fact I shouldn't do this. But because the design decision was use extension methods at the object level then everything gets this this method and that's a problem. So, as far as I'm concerned, I have a problem with this API because it basically

[30:36] (external link, opens in new tab) It it make it dirties up the IntelliSense name space of all the objects. That doesn't mean that I like the older design better, but I definitely don't like this one. This is the same test with two dependencies. One is a stub, the other is a mock. Create a stub logger with mock repository. Generate stub. And this is interesting about generate stub. Even if you assert was called on a stub, it still would never fail. That's a design decision and that's something that or an ammy

[31:11] (external link, opens in new tab) Actually caught at some point. Then we can say I want you to expect and this time again we're not using strings anymore if you've noticed I want you to expect what we have is actually a lambda expression and the way I read this lambda expression because we have to satisfy the compiler I want you to expect and this is another extension method okay so expect on a logger which is the fake logger

[31:43] (external link, opens in new tab) Expect this call to happen logger.Write write with yo that means that I'm expecting exactly yo to be sent in and if I wanted to do something different like expect any string we can also do that with write or mock and when that happens I want you to do throw a new logger exception so the expectation is actually a way for me to set up throwing an exception it's not really an expectation I will assert against.

[32:18] (external link, opens in new tab) But the API doesn't make this too clear. It says expect and then it says throw. And expect by nature means expected. So it might need to be verified later. But really here it means when this call happens through this exception. No need to verify. Then we have the mock service. We generate a mock and at the end we will verify a new mock service. The search was called that the service.Write

[32:53] (external link, opens in new tab) Got exception. Okay, the service right was called with this value. So we initialize login manager with the stub log and the mock service just like we did before but the assert look very different. So in this design we all we have extension methods on object and we have expectations and asserts directly on all objects in the system. It's our responsibility to make sure that you write the calls on the correct objects.

[33:25] (external link, opens in new tab) So so if you're going to use an ID with IntelliSense you're as far as I'm concerned the API doesn't use the strength of the IDE to help the user in terms of usability. it actually confuses the user more. Are there any questions or thoughts about this API? Now, this is basically the latest version of the API. It used to have an older version where you would do what's called a record and replay scenario where you would record what's going to happen.

[33:59] (external link, opens in new tab) Then you would say, "Okay, now go into replay mode." And then it would behave the way you recorded it before. So you would say record call write and then return three and then replay and now somewhere inside someone would call it it will return three but record replay turned out to be not so usable. I mean a lot of people liked it but then arrange act assert came in and it's much more usable. Okay,

[34:29] (external link, opens in new tab) Questions before we move on. Now, Rhino Mocks is very much used around the world. So, it's good to know this API. Now, the Moq or the Moq is the first package that that actually came in with the idea of arrange act assert for isolation frameworks. I think it was the first and Rhino Mocks was the first to come in and and remove the idea of strings from methods by using delegates like we saw before.

[35:03] (external link, opens in new tab) Moq was the first to say let's do a range act assert at the at the at the at the test level instead of record replay. So here's how we write the first test with Moq. With Moq when we want to override a class or create a fake one, we will say create a mock of ILogger. It's always a mock. Even if you're going to create a stub, it's still called a mock. Okay, so this is again a parent

[35:36] (external link, opens in new tab) That you tell what to to do. So create a mock parent really of ILogger. And then you would use mocklog.object object which is just like mock instance from NUnit Mocks and this time we don't have to cast it to ILogger because it's generic and because it's generic it's already the right type

[36:07] (external link, opens in new tab) Now here at the last line I have verification and verification I've made it a bit more complicated just to show where we can end up. But really what we can do is log right dot something like this. That's the most basic verification we could do with Moq mock log.verify that log. Now where did log come from? It's just a name we have to give to a variable in a lambda expression.

[36:38] (external link, opens in new tab) So it could be x, could be y, it doesn't really matter. But this always refers to this. Okay. So verify that the log.Write got called. What if we wanted to use a different argument to say that it got called I don't care with any argument. Then we have an API called it. It and then we can say is or is any is any is the one I use the most. So is any string.

[37:08] (external link, opens in new tab) And this satisfies the compiler and says I don't care what you got called with as long as it's any string. But I can also say it is or is in a range or is a regular expression. So it is we I can also do a lambda expression here. It is a string that string contains

[37:40] (external link, opens in new tab) It is a string where s dot contains a I think I'm missing something here. Oh yeah, I know why. It is a string. a. So we have to tell it what is the type

[38:14] (external link, opens in new tab) And that's basically it. So now it looks a bit more scary actually. Just the fact that the the API exists doesn't mean that we have to use it. What do I have too many of these? >> Semicolon. >> Another one. >> Oh, semicolon. No, there's another one missing. There we go.

[38:45] (external link, opens in new tab) You see that simple? I love compilers. So we are looking for log right that with a string. And now we would have to do this for any parameter that we care about. So once we choose this, we can say for the second parameter we can say another it is or we can say directly the parameter type whatever we want. But it becomes a bit horrible actually. So sometimes there is a actually a problem with frameworks like this is that the API usage becomes

[39:22] (external link, opens in new tab) A problem for readability. Let's look at the test with two with two with two dependencies. So now I have a mock of ILogger which is a stub and now we can say stublo log setup. So for the logger x when you say write with any string I want you to throw an exception.

[39:54] (external link, opens in new tab) When we say mock service we just send it in just like here and then we would verify it against the mock service that got written to. Another option that we can have is we can actually have a virtual method instead of an interface. So we can actually inherit from a class and override a virtual method and then we would have to use a special protected API that says I want you to go through a to protected mode and to set up a special

[40:26] (external link, opens in new tab) Method. Now because the method is not public we have to use a string. So we can say when write to log is called with yo it becomes verifiable and that's a horrible API but that's the way you do it and then you say verify in the end just like you used to do with NUnit Mocks. So here this is how you would make sure that a protected method called write to log which is virtual got called on a real class. So this is not an interface if you'll notice.

[40:57] (external link, opens in new tab) Let me just get rid of this inspection options and go away. So the protected API, you actually have to have a special using for it or you won't see it. It's this. If you don't have this using, you're not going to get this protected API. The reason is is that the creator of Moq didn't think it was a it was a great idea to override virtual protective methods.

[41:27] (external link, opens in new tab) He would rather that you just use public methods. So that's his way of discouraging you from doing that. Okay. And so again it's a design decision. Questions about Moq. So Moq is again w wildly used. Not wildly but widely used. Now let's take a look at the last framework which is proxy based

[41:57] (external link, opens in new tab) That's called FakeItEasy. FakeItEasy is my current favorite because I really like the API. This is the first test with FakeItEasy and all of these you can install with NuGet if you want. So we create a fake of ILogger. So everything with FakeItEasy begins with the letter a everything. So a fake of ILogger and we get back a fake.

[42:27] (external link, opens in new tab) Now we want to set up the the behavior. We can say a call to then we have a lambda that doesn't take any arguments. A call to fake.Write with a string that is ignored. throws a new exception. Okay. So now we can actually call login manager with the mock. We can also say a call to fake.Write with a string not m must have happened.

[42:59] (external link, opens in new tab) Now you usually wouldn't do these two things for the first test. This is just an example of how you set up the behavior. Okay. But this is really how the first test would look with FakeItEasy. you create a fake of ILogger then you ask a call to fake.Write with any string must have happened and if it didn't you get an exception. Now what's also good about FakeItEasy is that the error messages are really good. The error messages in Moq are really not good. They're they're not really helpful unfortunately.

[43:31] (external link, opens in new tab) And you're going to see that throughout the the day when you start using Moq as well. So you can see that the the design decisions around the API are very different. There's a single point of entry and this is something that also isolator did. So FakeItEasy is a bit later than isolator and I'd like to think that it used the isolator naming convent the isolator API conventions to do this. But regardless I really like this API because isolator doesn't use the the word a

[44:01] (external link, opens in new tab) Which I actually better I think than how isolated looks. Okay, let's let's move on and see what happens when we're talking about profilerbased frameworks. And at the beginning, you're not going to see any big differences except that with isolator, you have to put isolated attribute at the top of the class. And right now, you you see red here because I don't have a reference to one of the modules, but for demo purposes, it's not necessary. So, you put isolated here.

[44:32] (external link, opens in new tab) And this is important because without it isolator doesn't clean up fakes between tests and because you can use isolator to fake static things as well then suddenly you can have a test that tells a static method how to behave and then the test next after that might get the same behavior if it didn't clear out before. So this is something that is really important. You can also put it at any method level if you want it.

[45:03] (external link, opens in new tab) But you're doing this, it's as if you put isolated at the method level. So this is the first test with isolator. Again, the idea is that you have a single entry point. Everything starts with isolated. So isolate.fake.instance of ILogger. You get back a fake logger, which is an ILogger. Then we create a login manager with mock and we initialize it with fake ILogger. What's interesting is that again we don't have a parent.

[45:35] (external link, opens in new tab) We just directly tell how it's how it's going to behave or verify against the static isolate word. So isolate.verify dot was called with exact arguments. There's also a was called with any arguments. or was called with arguments matching and we have an empty lambda that just say fake ILogger.right with yo.

[46:06] (external link, opens in new tab) Now there's a big difference in terms of design decisions on what happens when you send in parameters to fake calls here. This is really what's important. If I said was called with exact arguments then this is considered into the asserts. If I said was called with any arguments, this is not considered. I can send in whatever I want because it's just to satisfy the compiler. Here's another example of the design the difference between from all the other frameworks.

[46:39] (external link, opens in new tab) Here I have a logger and a web service and I want the logger to always throw an exception. So I can say create a fake instance isolate.fake.instance instance of ILogger and I then I say isolate dot when called okay fake logger.Write and I'm actually using the real instance of fake logger when fake logger.Write writes with anything gets called. How do I know it's with anything? Because by default isolator ignores parameters.

[47:13] (external link, opens in new tab) So I can send in null. I can send in one. By default isolator will assume that I mean anything unless I say dot with exact arguments. So it's the opposite. In all other frameworks by default it takes into account what you're saying unless you say ignored or it is any etc. And the reason is does this is because most of the time you want to you don't care. So we want the test to be as less brittle as possible.

[47:47] (external link, opens in new tab) So usually we don't care because if suddenly you do care and the input changes suddenly the sets stop work working and you have to change all your expectations all your behavior. So anything really means anything. So it throws an exception on anything from this moment on to the end of time this will always behave this way. But if I had said this was called when called fake logger.Write Right.

[48:17] (external link, opens in new tab) So if I if I done this dot call original then what's going to happen is that the first time fake logger.Write gets called it's going to throw an exception but on the second time it gets called and from that moment on it's actually going to call the original method we faked. Okay, so I can actually set multiple behaviors just by calling it multiple times.

[48:50] (external link, opens in new tab) So always the last one is the one that gets considered. If there are multiple they just put in like in a in a queue. Now we have the fake web service and we say new login manager with mock and stop put the web fake web service and the fake logger and isolate.verify verify was called with any arguments fake web service.

[49:21] (external link, opens in new tab) Okay. So, so far there has been no difference in terms of how you use isolator than all the other proxy based frameworks. So, let's see where this difference actually comes into play. If we look at login manager with statics here we have a more interesting situation. The interesting situation here is that in here is login okay is not really calling an interface. It's calling a static logger class with a static method

[49:53] (external link, opens in new tab) And we want to check that it actually gets called. Now because it's static, we can't really replace it because there is no instance to replace. There's nothing to inject. If we were using a proxy based frameworks, we cannot replace it without refactoring the code to make it more testable. What if we don't want to do that or we don't have a way to do that? We're not allowed or it's not our code, etc. So if you wanted to check that static logger.Write write got called with isolator.

[50:25] (external link, opens in new tab) You would do something like this. You would say create a new login manager with statics, which is the class we just looked at. It's the this one. Sorry, it's this one right here.

[50:56] (external link, opens in new tab) Create the login manager with static call is login. Okay. And verify was called with any arguments. Static logger. We actually got call it directly. But this wouldn't work without us just telling isolator that we just want to track this static method for later. So we just have to say isolate fake static methods on the type of static clogger.

[51:28] (external link, opens in new tab) From this moment on all the static methods on this type will get flagged to be noticed later. So now I can actually check. Hold on. I'm going to answer your question. >> You will. Yes, you will answer me. Now, >> by default, this is the preferred way because usually I don't care about all the static methods if I don't care about one of them unless I'm actually testing one of them. But this way if I get new static methods later during in during my other designs next year,

[51:59] (external link, opens in new tab) My test will actually include those static methods by default. So, I don't have to change my test if I don't want to if I want to ignore them later. So, my test is actually more durable, more maintainable. I could pick and choose. I can say just ignore one single static methods if I wanted to. For example, I can say instead of this I could say isolate when called static logger.Write

[52:35] (external link, opens in new tab) With anything dot ignore call. From this moment on, this method will do nothing but it will be tracked. So I can actually verify it got called. So now I chose one method. But if tomorrow I'm going to get another method and another method that I'm going to need to to fake, then every time I'm going to need to go back to this test and all the other tests that need to fake it and add those extra methods. Now what's the question? The question was

[53:07] (external link, opens in new tab) If you want this test in parallel so the isolated u well obviously will create so it's it's a different I injection take taking place because it's when static member would have been messy otherwise so we can so this problem also goes away because currently we obviously we have the problems if we have some static members we avoid them as fast >> you lost me Can you ask? Can you ask? >> Yeah. Yeah. Okay. So I will not get into trouble if I run tests in parallel with that.

[53:42] (external link, opens in new tab) >> Yes, you will get into trouble >> with that. >> Yes. >> Still okay. >> Because currently as far as far as I remember it's not thread safe, but it is process or app domain safe because there's no problem there. So as long as different instances different app domains but it's not thread safe the different >> that >> yeah the different behaviors. Okay. Any other questions about this?

[54:15] (external link, opens in new tab) What if I wanted to verify that when static logger write actually throws an exception that it calls static web service. Right? Because we used we actually had that requirement before. I want to I want to I want this to simulate an exception and I want this to verify that it got called. Here's a way to do that. We can fake all the static methods of static logger or all the static meth and all the static meth static web service. We can also say look when when called static logger.Write dot will throw new logger exception.

[54:49] (external link, opens in new tab) You can see it almost reads like an English sentence. Then we call login manager with statics is login okay and we verify isolate verify was called with any arguments static web service.Write Right. So it's pretty simple without actually changing a piece of code. Okay. We can also get the various parameters. So we can actually say when called static web service write do instead we can actually change the behavior and say we get the context with all the parameters that were sent in and we can say text written to web service and we can actually override things if we wanted to just like registering to an event.

[55:34] (external link, opens in new tab) But these are more advanced scenarios. We don't have to worry about it right now. Let's take an even more advanced problem. What happens when we have something like this login manager with future object? So now in our code we have a new real logger.Write. Someone is actually saying new relogger. So even if we wanted to it's not static but we don't have a way to inject an instance because it's always creating a new instance.

[56:08] (external link, opens in new tab) Okay. But we still want to make sure it got called or we want to fake it so that we don't have a dependency problem. the same here. New web service.Write. How do we take care of that? So this is what it would look like. If we wanted to take over a future instance, then we would say we create a fake instance of real logger. And because this is a profiler based, I can create an instance of anything I want.

[56:42] (external link, opens in new tab) Even if it's a even even if it has a private constructor or it's not an interface really, I can say isolate.fake instance of real logger and that and call it a fake logger. And I want you to isolate. The next instance of this type with my fake logger. So now if I was to say fake logger when called throws an exception and then swap the instance then the next instance of real logger what's going to happen is that the call is going to be redirected to my fake logger and it's actually going to throw an exception.

[57:22] (external link, opens in new tab) So even if there is a new inside my my method call. Okay. Okay, so now I can also verify it was called verify was called with any arguments my fake logger because it's going to be replaced with the next instance. That's a very powerful feature. But it's not powerful enough because this test will only work for the one next instance. What if I already have a singleton instance somewhere living? How do I replace that? So in that case we can say swap

[57:55] (external link, opens in new tab) All instances of relogger with the fake logger. So now all future and existing instances will get redirected. Okay. And now that means that if I have a singleton I can just it will behave differently. But if I have a singleton I can also work in a different way. Let's say I have a singleton somewhere that looks like like this. My config settings instance dot

[58:27] (external link, opens in new tab) Machine name or something like that or username. Okay, now this is really a singleton. If I wanted this is the way a singleton might look like. If I wanted to, I could say isolate when called my config settings instance dot user name

[59:04] (external link, opens in new tab) Dot will will return Roy. So that will work as well. And the reason it will work is I'm just picking and choosing and actually saying, "Look, I want you to fake all this chain of things." So, they're all going to be fake actually. I want you to fake all the way through my config to my username. And that's actually going to be fake. Another powerful feature of most of these frameworks is that there's the idea of recursive fakes (external link, opens in new tab).

[59:39] (external link, opens in new tab) So if I have a fake object and that fake object has a property called person, that person is going to be fake by default as well. If that person has a property of a different person, that property is going to be fake as well. That means that if I have a chain of object that's going to be used inside my code, I just need one line of code to fake the the whole hierarchy. I don't my test will actually be more readable. This is something that Typemock Isolator pioneered

[1:00:09] (external link, opens in new tab) And the idea of recursive fakes and then other frameworks added that as well. Now with the proxy based frameworks this will only work if the properties are virtual or their interfaces otherwise it cannot fake them. With isolator this will work with anything. So private methods, public methods, static methods if they have a value they return the default value. If they have an object they return a fake. That's what they do by default. Okay.

[1:00:40] (external link, opens in new tab) So that was the big difference between profilerbased and proxy based frameworks. You can see that the differences in terms of abilities are huge. And what we're going to do now is we're going to do some exercises using Moq and later also isolator and FakeItEasy to actually drive this knowledge into our hands not just our minds. Any questions before we get started? Okay, let's take a 5 minute break for coffee and then we'll do the do the exercises.