Getting started with Mocking using Moq in .NET (Core, Framework, Standard)

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hello everybody I'm Lincoln this fit I'm gonna show you how we can use mock in order to do mocking in our unit tests in dotnet core mocking is put very simply the idea that because every class has dependencies and we don't want to go over the network or to the file system because of this dependence is like a repository that goes to a database for example we will mock to essentially simulate the behavior we expect this dependency to do in order to test the unique which is potentially just the public method we want to use that is using normally database code and I'm going to show you an example of this in an API that I have but before I do that I want to remind you that until the 2nd of February 20 20 I am running a giveaway in collaboration with JetBrains giving away 5 one year free keys or JetBrains writer writer is the ide i'm using and i highly recommend it for c-sharp in order to participate in a giveaway you have to click the link in the description and follow the instructions which mostly consists of you being subscribed to the channel and ringing the solidification Bell this video is part of a essential in you get pocket series so if you don't want to miss any episodes please subscribe wearing this identification well to get notified when I upload a new episode so as you can see here have a very basic customized controller in an API which has two endpoints 1 3 really which is the create a new customer get customer by customer ID and get all customers and that's it and you noticed all the data is using secure light which is a very lightweight database which I'm using in this scenario and I can show you here in postman that when I hit the endpoint I am getting just one user here and if I want to create a new one I can give it another name like this and then when I click send you can see that it created that and then if I get everything I'm getting everything and if I use the ID I am getting the one that has this ID and if it doesn't exist it will return the 404 not found so behaving sort of like a REST API and you can see here that all I have is a customer service which is using a repository and doing some mapping behind the scenes and the repository is connecting to the database and it's running these queries in order to do all the query you can find all this code in the description down below so if I close that I think you understand what's going on now in our controller and what I want to test is I want to test the customer service now the customer service as a class has two dependencies the I customer repository which is an interface which I'm implementing with my customer repository and the I logging service which I'm implementing with the testable logger because the dude Nicole logger is quite hard to test and it is walkable but I want to keep this video very simple we're gonna see tricky snares in a future video so for that reason I created the wrapper but allows me to unit test is very very easily and these are the two dependencies I want so what I'm gonna do now is we're going to test a couple of methods in here and the first thing I need to do is to create a test project I'm gonna go at my solution level and say new project and I'm gonna pick here the unit testing project in Rider and I'm gonna call it customers API dot mock and the reason why I'm using this name is because I'm gonna do a similar video with n substitute and fake it easy so stay tuned for that and no longer this X unit here c-sharp and that's all correct so I'm gonna add this so with that added here as you can see I'm gonna go ahead and add my project as a reference in order to use everything in there and then I get this unit test 1 + which I'm gonna rename now and the way I like to name my classes when I'm doing unit testing is abusing the name of the class that I'm testing so customer service and then I put tests as a suffix and this is now my class and what I'm gonna do now is I'm gonna write a method which reflects what I'm gonna test and for this scenario we're gonna use a public async task and the way I named my tests is I'm picking the name of the method I wanna test in this scenario I'm gonna go with get by IB icing so get by ID async and then I say should return customer when customer exists and this is my now in order for this to actually be found at a test as you can see in the very bottom here is I need to add the fact attribute and once I do that if I close this you can see that my test is now discovered now I like to break down my tests in three sections and I'm using the Triple A approach which is a range act and assert so in a range I'm gonna arrange everything I need to use for this test things I expect to see and stuff like that then act is where I'm doing the call of the method I'm testing in the scenario get by an IPS Inc and at the end I'm asserting the values from the Act section so as I said we're gonna test the customer service if this customer service has two dependencies one is potentially going to the console all the file system and the other one is going to a database and we don't want to do that in unit testing because new unit testing it's very isolated it doesn't go over the network or on the file system so what I need to do is I want to mock those two interfaces and them being interface is very important because only interfaces and abstract classes or abstract things can be under virtual I can actually be mocked other things cannot be mocked so keep that in mind so what I'm gonna do is I'm gonna add a new get package here and I'm gonna say mock and it's the first as you see here it's the most popular mocking framework for dotnet so it should be easy to find so this is now here and I'm gonna create my system onto test first so I'm gonna say private read-only I actually not a customer service which is what I'm testing and I'm gonna name it on the school system under test so SUT and I'm gonna create the constructor and in the constructor I'm gonna say new customer service and as you can see it needs two things the eye customer repository and the eye logging service so this is where a mock comes into place I'm gonna say private read-only mock of type I customer repository and here I say customer repo mock equals new customer repository mock and that's it I have my mug and then I need to do the same thing for the logging service so I logging service goes here and then log I just say logger Mach equals new logging service and now I have these new objects by default they have no behavior so if I do anything with these methods with these mocks my tests won't behave the way I want them to I will need to set them up and this is what I'm gonna focus with this video just set up of mainly methods and I'm gonna show you how you can do properties because that's the most common thing you will actually have to do and I'm also gonna show how you can verify that something has been called the exact amount of times in this box because this is the two most common scenarios that you need to be aware of there are the things like event handling and potentially things like callbacks but these are advanced features that you probably won't have to see in the day-to-day basis and there's plenty of documentation of that so I'm going to show you how you can get started and do potentially 80% of all the use cases with mock so first we need to say customer repo mock object because it's the first thing we have here and the next thing is underscore logger dot object and by object we're getting the interface which behind-the-scenes mock will implement with the proxy clause and that's how it actually mocks the behavior it creates an implementation in memory for that interface with that out of the way we're ready to write that test and let's see what we want the act to be like and the assert to be like right we wanna see that we can get a customer by IB this is the main goal so I'm gonna say result customer or just customer in fact equals oh wait SUT get by IB async and the ID will need to be a good so in our arrange we're gonna say VAR a customer ID equals good dot in your gooood and that's it and I'm going to copy the and paste here and this is what I want my act step to look like now of course I need to assert that other things about the customer are coming as expected in fact if I just do this now let me just bring this window up and I add an assert clause which says assert that equal and what I'm expecting is the customer ID and what I'm testing it against is the customer ID if I do that and I run my test you will see that the test will actually fail wait a second that's not what I'm testing against I want to test against the customer that I'd be here we go sorry for that so if I run this now we will see this failing and that's because it will actually not have a null because the mock is not set up let's see how we can set up the mock and actually let's see what this method looks like so as you can see here we have a call to the repository with get by ID a sink and this repository goes to a database and this is where we provide the customer ID and we get a customer bug or not and if we don't get one we get not bug and we also do some logging here so what we really want to move here and we have to mock this this is the get by ID async so how do we do that well we find the mock we want a mock so the mode class do we want to mock we say customer ripple mock dot setup and here we choose the method we want to setup in our scenario is that get by ib icing keep in mind even though they have the same name this is the service call the system under test this is the repo so don't mix them up that total different things this cost the database this goes to this so what we want is to verify that if we call this method with this customer ID and this word is goes here then this method returns a sink a customer DTO in this customer detail we're going to have to create ourselves so I'm gonna say customer dto equals new customer dto and this video will have the idea that I have here and the name that I'm gonna give it and that name well that would be my name so actually I will not even create here I will create it as a local variable so customer name equals make chapters here we go and I'm going to use that as the name and the reason why this is complaining is because the DTO actually stores this as a string so I'm gonna have to do a two string here but that should fix it and because this is an async method I'm gonna use the returns async method if this wasn't an async method I could simply do returns and provide what I'm returning you listen out of the DTO so this is now setup so that's it and if we run the same test with this setup I expect this test to pass and sure enough my test is actually passing because now the setup method of the mock is telling please return something that I created here in memory in this now the customer data so this is how this part works and not to verify that everything is mapped correctly as well we're gonna say that assert equal customer name and that should be equal with the customer dot full name also I want to avoid you see that if I replace this with the actual class which is a customer domain object this and this are totally different objects and what we're really testing here is that the mapping from one object to the other actually works fine so if I revert that and I run my test again you should see that my test is passing validating the behavior and now if I do cover selected unit tests you will see the unit test coverage window pop up here I can actually go to this method and show me exactly what line is covered by the tests and if I click here it also shows me the test that is covering this line test coverage is something that we used to see which test and whether a line is covered by a test that's best played and we can see here that this part is not test then this part is testing the customer is null behavior so let's go ahead and test that I'm gonna just copy the let's just copy the whole thing and create the test again with some modifications so just copied this and what I want to test is get my ID async should return nothing so renaming this nothing when customer does not exist we close this window so when my customer does not exist this returns nothing so none so I'm gonna just delete that assert step this will stay the same because this is the same I'm gonna delete that in the arrange and what I will say is that here I do not care what the ID is any ID in this scenario should return nothing back for that reason I'm gonna say that it is any good so any good should qualify for matching this setup and on any good in this scenario return none now why do I do this a lambda function approach is because if I remove the null here the null cannot actually be inferred to a type because it's the async method if this wasn't the acing it would work but know that this is how you do null here when you have an async method so this tells it that when this method is called with any good please return null and because this returns null here now we will fall under this little block which will return null so what am i setting against is get good by ID and I can simply say good dot new good because I don't care about the good here I could very much create one and use it in both places but in this scenario it does not really matter and I can say dot assert that null and customer and I'm gonna run this and this should also pause by the way the reason why I'm using the built-in assert of X unit and not something like fluent assertions or should Lee is because I'm I actually have video these two packages as well as part of this series so we're going to take a look at them then and as you can see both tests passed so this is the very basic scenario of setting up a method and in the same way you can also set up properties you could if we had a property you could say customer repo Mach dot set up property and you can also set up getters only the terms of documentation this is just showing you the most common scenarios you can find a link that description taking you to the Mach documentation and please leave a star to the project because I think it's a great project now if I run this coverage thing again you will see that it looks like everything about this is covered and that's because the test will actually traverse the method in its entirety but as you can see here we're also doing some logging which doesn't return anything but it is being called nevertheless and the reason why the tests are not failing here is because because this is a void this will just be essentially mapped to nothing and ignored so what we want to do and what we should really want to do if logging is essential to us or even a metric collection if you have an alerting system multiple metrics that should be very important to do is to ensure that these things are actually called and how do you do that with something that doesn't actually return anything what I'm gonna show you it's actually quite simple so I'm gonna create a new fact here and that will be a public async task in the same way and I'm gonna use the same method get' by ID async and I'm gonna say should log up up create yeah message when customer exists it's a long name but I prefer long names because they're very descriptive and I don't need to leave comments so that's why I'm using them and again I have my triple-a generated here and I'm gonna write the code that I need and ultimately the act will still be the same and in fact I can copy the whole arrange and act from my first test am I gonna grab paste that here so as you can see we'll still setting up a new customer to be returned here and we now we're going to change the assertion and one do I split these tests if the code is the same when the reason why I do this is because I like my unit test to test one thing only I could very much group them put the accession here but then what is the purpose of this test what is it testing is the testing that the user is not properly oh that my logging message is appropriate and correct so for that reason I split them now if you don't want to do that well feel free to not do it but I think the best practice to split them to make them clear so in the assert method now as you can see we have the same mocking but we also have the logger mock which we do not setup because we don't need to set up but what we need to do with it because it will be called here in fact here is to ensure that this message is called and it's logged in it correct and not to do that I'm gonna say logger Mach dot verify and this is what we're doing here we're verifying that something is called and what are we verifying we're verifying that log information with this message is called and that's not enough we also need to specify the parameters and the parameters is the customer ID so I'm gonna put that here and now this should be enough in fact if I just run this it should just pass and as you can see it does pass but in order to be more specific I want to put a comma here and say x once because I want to ensure that this will only be called once and if I run this now here you go my test did pass and you can also verify that something is not called and let's just show this with this other message here so I'm gonna copy that message and potentially this double click here is not what you would do in a realistic scenario but I'm gonna use this opportunity to show you how you can test that something is not cold so this should not be cold and for that reason and the parameters is again customer ID and for that reason I'm gonna say x dot never and this is never cold and you can see that if I just click dot you have things like at least and a number at most and a number at least once at most ones exactly and between we're gonna go with never in this scenario and if I run my test I expect it to pass in the same way and as you can see it did indeed pass so now I'm verifying but something that doesn't return something is called with the appropriate parameters in fact let me show you what it would look like if that wasn't the case so retrieve the customer with ID this is what my current test is doing but if I change the method with I do this and I could say something like end name or if I say sex successfully I probably misspelled that okay whose correct so if I change the message to successfully retrieve the customer with ID now if I check in this code without running the test on my CI runs them it will ignore this because my test will fail because the message here is not what the unit test is expecting so my unit test is failing and it's doing its job because it's making sure that this might be critical for the system you cannot just change it without updating the test as well or without knowing that there is a test these are the two basic things I want to show you about mocking in this context there's way more methods but I think they're much more niche than setup and verify so for that reason I want to stick to just that and if you want an advanced mock video please request it in the comments and I'll make one you can find the full documentation of mock in the description down below that's all I had for you for the day thank you very much for watching special thanks to my github sponsors for making these videos possible if you want to support me as well you're gonna find the link description down below leave a like if you like this video subscribe for more content like this and ring the bell as well to get notifications when I upload a new episode and I'll see you in the next video keep coding
Info
Channel: Nick Chapsas
Views: 144,997
Rating: undefined out of 5
Keywords: Elfocrash, elfo, coding, asp.net, .netcore, dot net, core, C#, how to code, tutorial, asp.net core, js, csharp, rest api, lesson, dev, microsoft, microsoft mvp, .net core, nick chapsas, chapsas, asp.net core 3, .net core for beginners, xunit, tests with xunit, unit tests, mocking in .net, mocking with moq, moq, nunit, getting started with moq, mocking for beginners, dotnet, .net
Id: 9ZvDBSQa_so
Channel Id: undefined
Length: 22min 10sec (1330 seconds)
Published: Mon Jan 27 2020
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.