Writing tests in .NET using xUnit - xUnit Tutorial

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hello everybody I'm Nick analysts we're gonna show you how you can use X unit in dotnet to write unit tests actually this probably the most popular unit testing framework currently being used even by Microsoft themselves so that's why I'm going to show that first but of course in the future video we're also going to take a look at any unit potential EMS tests as well even though I don't think many people use nowadays I'm gonna show you everything you need to know for actually to start now writing unit tests and know exactly what you need to use in which cases and how excu it works out of the box just before I move into the code I want to remind you that until the 1st of February 2020 I am running a giveaway in collaboration with JetBrains giving away five one-year free rider licenses right there is the ID I'm using my videos and I can highly recommend it if you want to enter the giveaway just click the link in the description and follow the steps which mainly include being subscribed and ringing the sub notifications but this feed is part of my essential nougat package series so if you don't want to miss any episodes make sure you subscribe during the solidification well to be notified when I upload a new episode so here I have a very simple xunit tutorial project and the only packages that I have installed are the following I'm using the X unit version 2.4 point 1 X unit dr. owner dot Visual Studio 2 point 4 point 1 and then the microsoft.net dot test dot sdk and that's all we need to start developing I have also created two classes one is a calculator class which contains some basic functions like add subtract multiply and divide and the other class is a good generator that creates a random good using one of its properties I'm going to use this class in this video to show you exactly how actually it works in all the scenarios that you can use it this video also assumes you know what unit tests are so I'm not gonna be explaining what that is I do have a TDD tutorial if you want to check it you can click the link on the top right corner of the screen right now so a couple of things about X unit first you should know that it's supported in dotnet core framework uwp and xamarin so we cover all the major dotnet frameworks you should also know that X you is an iteration over when you need any tries to fix in quotes some of the mistakes that people think any unit has something you should know is that X unit runs the tests by default in parallel but we can override it and I will show you how that works so let's just see how you can write a test next unit the first thing I'm going to do is I'm going to create a class and I'm going to name this class calculator test so we're going to see how we can actually write just test for the calculator class the first thing I will do is I will create a private read-only calculator field called underscore su t + su t means system under test so it is what we're actually testing right now and then I'm going to make a constructor and I'm going to initialize that field using a new calculator and this is what I'm going to be testing so in order to write a simple test and in this and I will be probably just a simple addition we have to create a public void and you can also have a public async task if you're using the async approach and this is now we're doing this all synchronously so I will just say avoid and I would say add two numbers should equal they're equal yeah I mean questionable naming but it describes what this test does and what you need to do for this to be recognized as a test by a div and actually I can pull here the runner I can move it to the right so you can see it clearly so here I will have my tests when discovered and what I need to do is I need to add the fact attribute and the moment I added you can see that it is now recognized as a test and I can actually just right click and run it it will now pass because there is nothing that can actually make it fail so what I will do is I will actually write some code so what I want to do is I want to say SUT dot add and we're gonna add five and then I will add something again so probably an eight and I'm gonna say at the end assert dot equal and what I want is the expected number which in this scenario is 13 and I want to check what is the actual number which is in the calculator as the value property and now my test should pass when I run it so this is how you write a very basic test and you can see here that the test has actually passed now this is testing two very specific things it's just in the 5 and the 8 number but what if I want to have more complicated signal like negatives well you might say just copy that create another test change the name like 2 and then make this minus 3 for example and these 3 and say that I'm expecting 0 so here we go we have two tests I'm running again all the tests and they should now pass but this is cluttering our class because the only thing that changes isn't the code but just the parameters so how do we permit erisa test in a way that we can have multiple cases with a single codebase well if I delete that and I copy and create a new one I will just delete the fact attribute and I'm gonna say at the end theory I should know here that the names I'm using and not the names I would actually use to name those tests but I want you to be able to recognize the difference between the tests of that why that's why I'm adding these theory at the end or I might add a fact or ignored stuff like that so what I want is this method to have two parameters one is in fact it's returning a decimal and let me just create a new line so 1 will be the expected so I am expecting this to return this number and then what I want to do is I won't have to two decimals first to add and potentially just another one called second to add I should know at this point that these tests when I run them they run completely in parallel by default and they do not affect each other because each test is running on its own instance of this class so the calculator won't be reused for both tests if you want to do that I will show you later in this video so stick around so we have that here and we have our three parameters now how do we make this run for different amount of numbers and in fact let me just change this to be first to add and second to add and expected here so here's our very generic code that should work with multiple values well first you need to add the theory attribute and now you will see that this is not compiling because theory methods must have test data how do we do that well what we're gonna do in this scenario is we're going to use the inline data attribute and we're gonna say the exact same test case as above expected 13 and add 5 and add 8 but then I'm gonna copy that and I'm gonna do the zero thing so I'm gonna say 0 minus 3 and when I add minus 3 and 3 they should make 0 and again a third one I can just say a hundred and then I have 45 and 50 you can have as many as you want in as many test cases actually this is redundant but I could cite when I add 0 and 0 it should return 0 that might be good has to have so now you will see when I run this that I will have one test here and three nested tests here and as you can see if I click expand these tests are treated as separate tests here so I am having 3 tests running with a single code base which is great now you might say what if I want to skip a test for a specific reason I don't want to be running in this specific running of my code maybe it's broken maybe I need to push a CI build and I don't want CI to fail because of the test well all you need to do is you need to use in the fact attributable theory fact attribute you need to use the Skip property and you need to set a reason for the Skip so I can say here this test is broken and if I save and I run my tests again you will see now that these tests will be marked as ignored and as you can see it only it also gives us the reason why this is ignored this test is broken so this is how you skip a test in X unit the next thing I want to show you is how you can actually have more complicated data as parameters because as your complexity becomes well more complex you might want to have different things not just numbers here or a list of many different things you want to test against and you don't want your attributes to have ten or fifteen different in line data so what do you do let's say for example that we have a public static I enumerable of object and the reason why I'm creating this is because I want to create test data so I'm going to say test data here and then let me just import that and what I'm gonna do is I'm gonna say yield return and I'm gonna return a new object array which has in a similar fashion the expected so I'm gonna say 15 but then it accepts an array of parameters and this means that I can have an infinite amount of numbers well technically it's not infinite but in theory and an unlimited amount of different numbers I want to add or subtract from each other so I'm gonna create an array of decimal here which is a decimal to one add to a new array of decimal and then in here I can put my decimal so what adds thirteen or sorry fifteen well it's ten and also five makes 15 but what if I want to have a different type of representation here I can say five plus five plus five also makes sixteen you can also have multiple other tests here so in this scenario you might want to say okay how do I make this negative ten well I'm adding negative 30 and 20 and which this should give me negative ten and the test I'm going to write for this scenario is a very similar to this but instead of having two numbers if we have many numbers and the way I do this is I'm going to remove that and I'm going to say params stands for parameters and then decimal array and then value is to add and Bram's will allow the method to accept an infinite amount of decimals so what I will do then is I will say values to add dot for each and I'm going to create a for each loop I'm gonna say value and I do system under test add the value and how am I using this I new marble here what it's actually fairly simple first we need to use a theory again and now we need to say member data which is another attribute and I'm going to use the name of the method I will be using the member will be using and this is it so now if I run my tests as you can see here I actually have some failures as well the - are ten did not happen this might be something related to my code let's just do bug it and see why this is breaking it could be very obvious to you but I cannot see it so I'm debugging into the code and I'm having minus 10 so my value is minus 10 and then if I oh wait a second yes I totally messed up here well this is why your unit testing so what I want here is this to be my actual outcome so I move that here and then this should be like this so now if I run this this should pass assuming yes my math is right so that's really funny so as you can see we have two here we have three here and again we have two here and you can have as many as you want as long as they add up to this number and this is how you use member data which is essentially an ienumerable in your class to create a single test pyro when you can have as many as you want here and you can even auto generate some now what if you don't want to use a method you wanna go oh they call it necessary the clean way but if you have a huge amount of data and logic to generate the data it might be the clean way so what if you want to use a dedicated class in this scenario well here's where we can actually just use a class data attribute and the way to do that is first you need to create a public class and just creating it in the same class so I don't have to create a new one and I'm gonna use this for division that I'm gonna say the vision test data goes here and this class needs to implement the I enumerable interface of object array and I need to implement get enumerated methods I don't need to touch the sorry I don't need to touch this one at all I need to implement this and this one just returns the data I want so what I'm going to use is the following data in similar fashion are going to copy this which is a yield return and I'm gonna say that I want 30 back and in order to get 30 I need 60 divided by 20 what I'm at is great and then I won't zero that's another good case and in order to get 0 and X 0 divided by well really anything so I'm going to say divided by 1 and last but not least if you divide the same number with each other they return one so I'm gonna say 50/50 should give me 1 and now because this implements that ienumerable of object array I can just copy that same method the member data 1 I'm going to name it the divide many numbers not should equal very cool but dividing many numbers favoring a donor it's a bad name for a test but I'm just gonna use it to go through that and when I'm showing you adjust the framework and instead of member data I'm going to use class data not class data and I'm gonna use the type of the class I want to use for X unit to pick it up so you need to do is say type off the class which is the ienumerable of the object array so running the those tests now should create an equal amount of nested tests here and they should all pass and as you can see divided many numbers theory works like charm so these are all the things that you can do all the basic things that you can do with facts and theories and using memory data and class data and also inline data now something I should point out about X unit is that like I mentioned all those tests run in parallel but what if you didn't want to use those tests in parallel well you need to create a new empty class and call it a dinner collection behavior override something like that and delete everything from that class even the namespace and here I need to say assembly then I don't do that collection behavior and then I need to say disable test paralyzation equals true and this will disable the test from running in parallel and even though those are very quick tests if I run through you might actually see that they run one after the other well you could include my pieces too fast but if I was adding a delay there you would be able to see it so this is how you make test run known in toilet so sequentially also it is worth pointing out that these tests actually run in parallel because they're not part of the same collection and now you might say what are collections and I'm going to dive into that right now because let me just delete this class real quick because X unit has this cool concept called collections and it allows you to group different tests into smaller well collections and you can do cool things with it like if you take this outside of a unit testing ID and you go to the acceptance testing or integration testing you can actually use collections to run many tests using the same context so what I mean well I have the good generator here so what I'm gonna do is I'm gonna create a good generator test class I'm gonna show you a couple of cool things the first thing I want to do is rename this class from this name to GUI generator test one and I'm also going to create in the same class a second one so at two and then in here I'm going to have again the private read-only GUI generator will called good generator and I'm gonna set it in the constructor to a value anew of itself and I'm also going to use the private read-only I test output helper because I want to put some stuff in the console from my test and I can just inject this from the constructor it's working out of the box in X unit and then I need to create a single fact which I'm gonna call public void just just good test one and you'll see that I'm not really testing for something but I'm showing you how you can create collections and use the I class picture to reuse the same context in all of your tests so have a GUI test one here and I will leave this class empty for now and I will say good equals GUI generator dot random good ID and then I'm gonna say output dot write line and then string interpolation I'm gonna say the grid was and then the GUI text and I'm going to create another one as well and I'm going to call this too and the code will be exactly the same and why am I doing this well if I run those tests what do you expect happening from what you've heard until now what will happen is these tests class will be instantiated twice one for each test and the gooood I'm expecting to be completely different so this is f40 and the other one is DD a so completely different goods which means that these classes were completely independent of each other when it comes to instantiating but what if I don't want that to be the case what if I want to reuse the same system under test or even the same context outside of the system under test to keep some data from test to test well what you need to do is you need to implement the I class fixture class and then you provide your context in this narrow form it will be the GUI generator itself and instead of instantiating it in the constructor this allows me to inject it in the constructor as you can see here and now it's unit will say this and we'll say okay I know that this is the context you're expecting so I'm going to reuse this specific instance in all of the tests and if in fact if I just run those tests again what you should say is now the grid should be exactly the same so d4 - and d4 - which means that this instance injected is reused on every single test this opens a huge window when it comes to especially integration testing that you want to just do something sequentially and even if you disable the parallel testing you can do stuff like that or if you don't care about polarization you can still reuse the same database connection if you want to do some database stuff here and something I haven't mentioned is that xunit are supposed to any unit which is using the setup and I think it's called teardown attributes to do the setup and teardown xunit doesn't use that all the initialization should happen in the constructor that is the pattern and all the disposal should happen in the dispose method and let me see if there's there is not okay so the way to do that is you need to also implement the eye disposable interface and this will add let me just implement the missing member it will add the dispose class and let me just show you how about words I will just print something so the class was disposed and if I run the test again you will see that first I'm getting the good and then the dispose method is called and my class is automatically disposed so if you want to do any clear down any deleting of the database stuff if you use it for that reason you can do it here so yeah with that out of the way let me just delete this because I don't need it in this scenario now doing this class picture thing for a single class is fine but in a bigger system or in a bigger testing scenario you might want to use the same context in multiple test classes what you need to do for that is first you need to create a collection definition and how do you do that I'm gonna create a class called public class good generator definition or collection definition this is up to you and this needs to implement the my collection picture interface and in here I'm going to use my context which in this scenario is the GUI generator and this will be an empty class it doesn't have anything what it does have though is the collection definition attribute and this attribute requires a name and as you can see the other parameter in this method is the disable fertilization so you can tell that in a system where we're combining many classes it might be wise to disable parallelization if you want things to happen one after the other but I'm gonna leave it on by default for now and here I need to specify the name of this collection so X eunuch knows which part are of the same collection so everything with the same name will be run in the same context in the same grid generation method we'll using the same regeneration math class sorry so in this scenario it will be good generator so every class that has this as their collection name will use the same shared context I'm just saying this over and over again because it's very important to understand and now I don't need the I class picture anymore I am leaving this year as well though I am still injecting the GUI generator from the constructor but now execute will figure it out because I'm adding the collection attribute and of course I need to give it a name and the name has to be what I have in my collection definition that's how excute will know that this is what I'm asking for and now just to prove the point I will do this again and I'm going to rename this class to two and as you can see of course I have to change the constructor obviously and now I should have two classes yeah one and two but if I run just those two classes now what I want to say is every single one of them should have the exact same good in their print so if I expand to show you e9 8 e9 8 e9 8 in nine eight do you mind if I delete that well first they wouldn't run because they wouldn't know where the injectable is coming from but if I did remove that and I just initialized here and let me just quickly do that for the other class as well then obviously if I run them again every single one of them will have a different good because yes you say da db9 be d3 and so on and so forth and that's because nothing connects them they're not sharing the same context so this is very important to understand the next unit because this collection attributes and this AI collection feature can be a huge time saver when it comes to things like automated integration testing with X unit which X unit it's totally capable of so it's not just for unit testing those are all the basics I want to cover in this video you can find all the code in the description down below after watching this video you should be able to create your own unit test with X unit from scratch because these are all the main features that you need to be aware of special flex my github sponsors are making these videos possibly if you want to support me as well you're going to find the link the description down below leave a like if you like this video subscribe for more content like this and ring the bell as well to be notified when I upload the new episode and I'll see you in the next video keep coding
Info
Channel: Nick Chapsas
Views: 120,922
Rating: undefined out of 5
Keywords: Elfocrash, elfo, coding, asp.net, .netcore, dot net, core, C#, how to code, tutorial, asp.net core, javascript, js, csharp, rest api, development, lesson, software engineering, dev, microsoft, microsoft mvp, .net core, nick chapsas, chapsas, asp.net core 3, .net core for beginners, xunit, tests with xunit, unit tests, acceptance tests, integration tests, tests in .net, dotnet, .net
Id: 2Wp8en1I9oQ
Channel Id: undefined
Length: 25min 50sec (1550 seconds)
Published: Thu Jan 23 2020
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.