Unit Testing C# Code - Tutorial for Beginners

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
[Music] so what is automated testing is it a replacement for manual testing do I really need it how should I do it should I write my tests first which we call test-driven development or TDD or should I write the application code first maash I don't know what to test these are frequently asked questions about automated testing and in this course I'm gonna answer all these questions one by one so let's start with the first question what is automated testing automated testing is the practice of writing code to test our code and then run those tests in an automated fashion so with automated testing our source code consists of application code which we also call production code and test code here's an example imagine you have this function somewhere in your code it's a basic calculate function that takes an input and depending on some conditions it returns different values if you want to test this function manually you have to launch your application in the browser perhaps you have to login or maybe you have to do a few clicks here and there to get to a page where this function is used then you'll have to fill out a form submit it and see the result of this function on the screen and then you have to repeat all these steps each time using different values in your form as you can see this is very time consuming this workflow to test this function may take several minutes every time now to make matters worse this is not the only function in your application in a real application you have tens or hundreds of functions like this as your application grows in size and complexity the time required to manually test all the different bits and pieces increases exponentially so that's why we use automated testing with automated testing you write code and directly call this function with different inputs and verify that this function returns the right output now you can rerun these tests every time you change your every time you commit your code to a repository and before deploying your application with this approach you can test all the execution paths in this function in less than a second you can write several hundreds or thousands of automated tests for various parts of your application and run them all in just a few seconds but there are more benefits to automated testing and that's the topic for the next lecture recently a student of mine asked me maash why on earth should be write code to test our code when we can just run the application and see the result well in the last lecture you'll learn that with automated tests you can test your application code on a frequent basis and in less time but this is not the only benefit of automated testing the most important benefit is that you can catch the bugs before deploying your application and this is extremely important because it allows you to deploy your application with more confidence have you been in a situation where you finish all the work deploy your application left the office thinking everything is working and then got a call from your boss or an end user telling you that one of the major functions of the application is not working then you had to go back to the office and you thought that was a quick fix but you ended up staying there until midnight that's why you should write tests to reduce the number of bugs that will go into production now note that I'm not saying that with automated tests you're gonna release bug free software that's not true but you can certainly reduce the number of bugs and improve the quality of your software another benefit of automated tests is that they allow you to refactor your code with confidence refactoring means changing the structure of your code without changing its behavior if you extract a few lines of a method into a separate private method that's refactoring if you rename a method that's refactoring too you're changing the structure of your code to make it cleaner and more maintainable but you're not changing the functionality when you don't have automated tests every time you refactor your code you have to manually test every part of the application that could be affected by your refactoring and this is very painful because first of all it's time consuming and second as your application grows you may forget about the parts that need to be tested with automated tests you refactor your code you run your tests and make sure you didn't break anything that used to previously work and finally another benefit of writing tests is that it helps you focus more on the quality of the methods you're writing you make sure that every method works with different inputs under varying circumstances next I'm going to talk about different types of tests in automated testing we have three types of tests unit tests integration tests and end-to-end tests a unit test is what I showed you earlier in this section you test a unit of the application without its external dependencies such as files databases message queues web services and so on now note this key word here external dependencies this is really important as you will find out shortly so these unit tests exercise your code without any external dependencies they are cheap to write and they execute fast so you can run hundreds of them in just a few seconds and this way you can verify that each building block in your application is working as expected however since you are not testing these classes or components with their external dependencies you can't get a lot of confidence in the reliability of your application so that's when integration tests come to the rescue an integration test tests a class or a component with its external dependencies so it tests the integration of your application code with these concrete dependencies like files databases and so on again note that I'm emphasizing the word external here these tests take longer to execute because they often involve reading or writing to a database but they give you more confidence in the health of your application now traditionally an integration test is defined as a test that takes a few units or classes and test their behavior as a whole so based on this definition if you test two classes together some people believe you're writing an integration test and not a unit test even if none of these classes talk to an external resource like a database chances are you've heard this definition before now I tell you what this definition is a great recipe for writing fragile tests that are coupled to your implementation detail so as you change the implementation of your classes these tests are gonna break and you will end up wasting a lot of time fixing them not only won't they give you any values but they actually slow you down I'm going to show you an example of this later in the course when I talk about fakes and mocks if you have done unit testing before and failed chances are you follow this definition so once again a unit test tests a class or multiple classes without their external dependencies they test a unit of work an integration test tests a class or multiple classes with their external dependencies we also have another type of test called end to end test that drives an application through its user interface there are specific tools built for creating end-to-end tests one popular tool that you might have heard of is selenium which allows us to record the interaction of a user with our application and then play back and check if the application is returning the right result or not these tests give you the greatest amount of confidence about the health of your application but they have two big problems the first problem is that they're very slow because they require launching the application and testing it through the UI so every test is going to launch the application potentially log in navigate to an internal page submit a form and inspect the results very slow the second problem is that there are very brittle because a small enhancement to the application or a small change in the user interface can easily break these tests [Music] so now you know about the different kinds of automated tasks unit tests integration tests and end-to-end tests but what kind of tests should you write in your application for hell all of them this is what we call the test pyramid this pyramid argues that most of your tests should be in the category of unit tests because these tests are easy to write and they execute quickly but since they don't give you much confidence about the health of your application you should have a bunch of integration tests that test the integration of your application code with its external dependencies these tests provide many advantages of end-to-end tests but without the complexities of dealing with the user interface and finally you should write very few end-to-end tests for the key functions of the application but you should not test the edge cases with these end-to-end tests you only test the happy path and leave the edge cases your unit tests now this pyramid is just a guideline it's not a hard and fast rule that you need to follow in every application the actual ratio between your unit integration and end-to-end tests really depends on your project unit tests are great for quickly testing the logic like conditional statements and loops if you have methods with complex logic and calculation you should test them with your unit tests earlier in the section I showed you an example of a calculate function unit tests are ideal for testing these functions because you can quickly test all the execution paths of these functions in less than a second manually testing this functions through the user interface takes significant amount of time and is prone to errors however not every application has complex logic and functions like our calculate function you might have an application that simply reads some data from or writes it to a database in that case you may need more integration tests than unit tests so in summary this test pyramid gives you three recommendations first is to favour unit tests over a Qi or end-to-end tests because these unit tests are the fastest to run and cheapest to write and they're very precise so they can pinpoint exactly where something fails they give you rapid feedback second is to cover unit test gaps with integration tests and finally use end-to-end tests sparingly only for the key functions of your application the right balance is different for each project on each team at the end of the day you need to use your own judgment to determine what kind of test you need to write for different parts of your application - right unit and integration tests you need a testing framework there are several testing frameworks out there but the most popular ones are an unit which is one of the earliest frameworks out there we've got m/s test which is Microsoft's testing framework built into Visual Studio and X unit which has gained more popularity over the past couple of years all these frameworks give you a utility library to write your tests and a test runner which runs your tests and gives you a report of passing and failing tests which framework is better it depends who you ask and what their definition of better is different people love different tools so here's my suggestion don't get hung up on the tooling in this course our focus is on the fundamentals of writing quality tests that give you value that's what matters you can always use a different framework as you move from one project or team to another in this course we're gonna start with MS test because that's built into Visual Studio and doesn't require any additional steps but shortly after I'm gonna show you how to install and unit and run annually tests in Visual Studio you may use either of these frameworks as purely your personal decision but for the majority of this course I'll be using an unit because it has a longer history than MS tests and I personally find it a more elegant testing framework now an optional tool that I highly recommend is resharper because it has a faster and more powerful test runner than the one built into Visual Studio just to let you know resharper is a commercial product and I'm not their affiliate you may decide to buy a license or not that's entirely your choice what I want to emphasize is that you do not need resharper to write or run tests but I use resharper because it's a huge productivity booster another optional tool is writer if you like Visual Studio plus resharper but you think Visual Studio is too slow for you then highly recommend you to try writer writer is basically a cross-platform IDE built by JetBrains the same company that has made resharper so you have a super fast IDE plus resharper with the exact same shortcuts that you use in Visual Studio in this course I'm gonna record the first few videos with Visual Studio because that's the default IDE for maturity of you but later I'm gonna switch to writer because that's a lot faster you can use Visual Studio with or without resharper that's perfectly fine your focus should be on the fundamentals of writing good tests and not the Thule in the next lecture you're going to write your first unit test so download the zip file I have attached to this lecture this is a visual studio solution that includes some code you're going to test throughout this course hi guys maash here I hope you're having a fantastic day or night wherever you are in the world this tutorial you've been watching is actually part of my complete unit testing course for c-sharp developers and what you see here on YouTube is actually only the first section of this course the complete course includes more than five hours of high quality content with plenty of exercises and challenges that will help you really master unit testing in case you're interested to enroll in the full course I've put the link for you in the video description and if not that's perfectly fine continue watching as the next section is coming up all right in the slingshot you're gonna write your first unit test so here we have this project called test ninja that I'm gonna use throughout this course I give you the link to this project in the last lecture but if you miss that you can see it attached to this lecture so here we have this folder fundamentals let's take a look at this reservation class so imagine you're building an application for reserving a table at a restaurant our reservation class has currently one property which specifies the user who made this reservation now in a real-world application this class can have many other properties but we don't want to get distracted with too much detail this is the method we want to test can be cancelled by a given user so here I have implemented a simple business rule if the user is admin or the user who made this reservation they can cancel this reservation otherwise they can't cancel this reservation ok and if you scroll down you can see our user class very simple with one property is admin so let's go ahead and write the first unit test for this method here in the solution Explorer I'm gonna add a new project to the solution so add new project under installed visual c-sharp test you should see this template unit test project if you don't see it here chances are you have not installed Visual Studio property so go ahead and download the latest version of Visual Studio currently I'm using Visual Studio 2017 Community Edition so here we select unit test project and we give it a name so the name of our main project is test ninja and I'm gonna call this project test ninja dot unit tests this is the convention we follow to organize our test projects we want to separate the unit tests and integration tests because unit tests run quickly whereas integration tests take more time we want to separate them so we can run unit tests more frequently and integration tests before committing our code to a repository okay let's go ahead so Visual Studio creates this new project and you can see here we have a file unit test one is a simple C sharp class that has the test class attribute and it has one method called test method one with this attribute test method these two attributes you see here belong to m/s test framework so the test Runner we have in Visual Studio looks at all the classes decorated with the test class attribute then it looks at all the methods in this class decorated with the test method attribute and it will run them so the first thing I want to do here is change the name of this class so press ctrl R and then R again now you can rename these I'm gonna call this reservation tests because we are testing the reservation class so the convention we follow is the name of the class + tests enter now similarly I'm gonna rename this method once again ctrl R & R the method I wanna test is can be canceled by now here we add an underline we specify a scenario on the line again and expected behavior what is this let's go back to our reservation class when write two unit tests for this method we want to test all the scenarios what scenarios do we have here we have three scenarios one scenario is when the user is an admin the other scenario is when the user is the same person who made this reservation and the third scenario is when someone else tries to cancel this reservation so here we have three scenarios or three execution paths so there are three ways to get out of this method that's why we call this three execution paths okay so back to our unit test class the first scenario we want to test is user is admin now what is the expected behavior if the user is admin this method should return true so returns true this is the convention we use to name and organize our test methods every test method has three parts the first part specifies the name of the method under test the second part is the scenario we're testing and the third part is the expected behavior now inside every test method we have three parts a range act and assert this convention is called triple-a or arranged act and assert the arranged part is where we initialize our objects we prepared the object we want to test in this case we want to create an instance of the reservation class so we create a reservation object new reservation now here the reservation class is not recognized so you need to press ctrl + period and in this context menu select add reference to test ninja okay so we have a reservation object the act part is where we act on this object and that basically means we're gonna call a method that's the method we're going to test in this case reservation dot can be cancelled by now I want to give it an argument in this case we want to give it a user that is an admin user so here I create a user object and set is admin to true so this is the act part now we want to get the result and verify that it's correct so I'm gonna store the result in a variable called result and in the assert part we verify that result is correct in this case result should be true so here I'm gonna use one of the helper classes in Emma's test framework that is called assert this class has a bunch of static methods that we use to make an assertion for example if you want to compare two objects we can use are equal we also have other methods here like is false is instance of type is not instance of type and so on so here we want to assert that this result is true so we call assert dot is true and pass result so this is how we write a unit test now to run this test we go on the top from the test menu go to run and select all tests this is what I don't like about Visual Studio because here we don't have the ability to run only a particular test method like this test method we wrote in this lecture we can only run all the tests in this project and that's why I like resharper because with resharper I can run only this test or I can run all the tests in this class so it's more flexible I'm going to show you that later in this section so let's go on the top from the test menu run all tests and note this shortcut remember this so you can quickly run all your tests they should open this text explorer window if you don't see that you can find it on the top under test windows test explorer okay so you can see we have a passing test we have a green mark you can see the name of our test method and the time it took to run this test in a real world application you're gonna have hundreds or thousands of unit tests so when you run your tests this window is going to be populated with all the tests in your application now let me show you an example of a failing test so I'm going to go back to the reservation class and create a bug in our code so here I'm going to return false let's say the developer who wrote this code made this mistake as I told you before with unit tests we can catch bugs before deploying our application so when we create a unit test class and verify the expected behavior of a method in this case you're verifying that this method is returning true with this unit test we can catch bugs earlier and the software development lifecycle so back to our test Explorer window I'm going to run all the tests again this time our test failed so you can see the benefit of unit tests in action now here is an exercise for you as I told you before this method has three execution paths or three scenarios I want you to use what you learn in this lecture and write the other 2 unit tests for this method in the next lecturer you're going to see my solution in the last lecture we renamed this class to reservation tests but apparently the rename refactoring feature in Visual Studio didn't work properly because the name of the file is still unit test 1 so I'm gonna rename this to reservation tests dot CS with this convention you can easily find all the tests for a given class ok beautiful now that's right the second unit test so I'm gonna write a public void method and by the way all your test methods should be public void so here we're gonna use our convention to call this method the first part is the method on the test that is can be canceled by the second part is the scenario so let's say we want to test the scenario where the same user who made the reservation wants to cancel this reservation so same user canceling the reservation now the third part is the expected behavior what do we expect this method to return you should return true ok now inside this method we should have three parts arrange act and assert in the last lecture I added comments to separate the arranged act and assert parts but in a real world scenario you don't necessarily have to do this if your test method is short and clean so in the arrange part I'm going to create a new reservation object so reservation it's a new reservation in the act I'm gonna call reservation can be canceled by now here I want to simulate a scenario where the same user is canceling this reservation so I'm gonna create a user object here you and first of all set the made by property to this user so this user created this reservation before now I want to pass the same user object as an argument to this method user now we get the result and store it I finally make an assertion so we assert that result is true so now with these vertical spaces I have added in the code you can see the arrange the act and assert parts back in our test Explorer window let's run all the tests so we have one failing test and this is because in the last lecture I created a bug in our code so let me change this here we return true now back to our test class this new method I created here is not picked up by test Explorer we don't see that here why because we forgot to decorate it with the test method attribute so that's why you should decorate every test method with this attribute so it can be picked up by the test runner now save back in test Explorer run all now we have to passing tests beautiful now let's write the last test so I'm gonna start with test method and public void can be canceled by the third scenario is a user trying to cancel someone else's reservation so another user canceling reservation what is the expected behavior this method should return false so return false once again in the orange part I'm going to create a reservation object new your reservation and the act part we call can be cancelled by now here we want to deal with two different user objects so here I can pass a user object and when initializing the reservation I can set made by two different user object and finally we need to store the result here and assert that result is false so is false result now let's run all the tests so we have three passing tests beautiful so I have renamed this test method to make them more consistent and easier to read so we have three scenarios admin canceling same user canceling and another user canceling one thing you can see about these tests is that they act as some kind of documentation about our source code this is another benefit of writing tests imagine you join a new team they give you a new project and your task is to make some modifications to a class if that class is properly supported by a bunch of JUnit tests you can easily figure out what the responsibility of that class is now let me show you another benefit of writing tests earlier in this section I told you that once you have tests you can refactor your code with confidence so back in our reservation class I don't like the way this method is implemented it looks very amateurish so I'm gonna refactor it and then run all my tests and see if I've broken anything or not so the first change I wanna make here is instead of having two if statements I'm gonna have one if statement and use the logical or operator so if user is admin or made by equals user we're gonna return true otherwise we're gonna return false now back in test Explorer run all the tests so my tests are verifying that our application is still working I have not broken anything I can take this to the next level so instead of having this if statement here and then return false I'm simply gonna return the result of this expression now we have only one line of code here once again we run all the tests all the tests are passing our code is much cleaner and you can see another benefit of writing tests so far you have seen Emma's test in action in this lecture I'm going to show you how to use an unit which is my preferred testing framework so an unit is not part of Visual Studio and if you want to use it you need to install a couple of NuGet packages so open a package manager console make sure to select test ninja that unit tests and the project drop down list now we need to install a couple of packages so install - package the first one is any unit and make sure to set the version to the same version that I'm gonna use in this video so you will have the same experience so - version three point eight point one beautiful now the second package install package and unit three test adapter we need this package to run and unit tests inside visual studio because by default the test runner that is built into Visual Studio only recognizes MS tests so set the version here as well this one is three point eight point zero so it's not exactly the same version as any unit because these two packages are developed independently but these two versions are compatible okay beautiful now with n unit we have different attributes so instead of test class we use test fixture now we need to import this type so press ctrl + period and select the first item using n unit dot framework okay and instead of test method we have test like this and finally we need to modify how we make assertions so here we have a compilation error because Visual Studio doesn't know whether we're referring to the assert class in any unit framework or MS test so I'm going to go on the top and remove this using statement for importing Microsoft unit testing framework so delete the compilation is gone so you can see this assert class has the same API as the assert class in MS test but here we have a different way of writing assertions which is more readable so another way to write the same assertion is like this assert that result is true it reads like plain English also another way is to write assert that result equals true so we can add a boolean expression here which I approach you choose is purely your personal preference there is no technical differences between these three ways of making assertions so in this lecture I'm gonna use the second for delete and delete all right now let's run these tests so once again on the top test run all tests so all tests are passing beautiful so this is how you use any unit inside Visual Studio now if you use resharper you don't need to install and unit test adapter because the test runner that comes with resharper automatically picks and unit tests the same is true if you use the writer ID when you get started with automatic testing a word that you hear often is test-driven development or TDD test-driven development or TDD also called test first is an approach to build software with TDD you write your tests before writing the application or production code the first time I heard this I asked how on earth is that even possible how can we test the code that we haven't written chances are have the same question so let's see how you start by writing a failing test this test should fail because you don't have any application code that would make it pass right then you'll write the simplest application code that will make this test pass the absolute simplest you don't want to over engineer here you don't want to design a class diagram with a zillion classes and methods use the simplest implementation that would make the test pass then refactor your code if necessary these three steps are the foundation of TDD you repeat these three steps over and over until you build a complete feature now what is so special about TDD well first is that your source code will be testable right from the get-go you don't have to make any changes your code to make it testable second is that every line of your production code is fully covered by tests which means you can refactor and deploy with confidence and third is that it often results in a simpler implementation when you start with a big class diagram chances are you're over-engineering and making the solution more complex if you write enough code to make all the tests pass and that solution works there is no reason to write more code the fact that all your tests pass means you've fulfilled all the business requirements so unless there is a new requirement you don't need to write more code and if there is a new requirement you start by failing tests so this is TDT in TDD we write our tests first and that's why we call this approach test-driven development so our development is driven by our tests in contrast to TDD or tests first we have code first which is what you have been doing so far you start with your application code and then you write tests which approach is better it depends who you ask in theory TDD is more promising because of the benefits I told you but in practice sometimes it can get really complex and it may slow you down if that's the case it's better to switch to the code first approach and write your tests after in this course our focus will be on the code first approach so we can master the fundamentals of testing once you master the fundamentals then you'll be ready to start your tests first journey TDD really requires a separate course and I'm not going to talk about it throughout this course but if you're interested potentially in the future I can create a course on test-driven development all right now let me give you an overview of how I have structured this course real quick in the next section you're going to learn the fundamentals of unit testing in this section we'll be looking at characteristics of good and trustworthy unit tests we'll be looking at naming and organizing tests writing some basic unit tests as well as creating parameterised tests once you master the fundamentals then we'll be looking at the core unit testing techniques in this section in each lecture I'm going to show you an example of a function to test each function shows you a scenario that you see in a lot of real-world applications the following section is all about exercises so in that section I will give you three unit testing exercises and you will have a chance to put what you learn in the first two sections in practice for each exercise you can see my solution as well now up to this point all our unit tests are four simple classes that don't have any external dependencies but in the real world our code often talks to a database and web servers and so on so section 5 is all about dealing with these external dependencies in this section you will learn about concepts such as dependency injection and marking the following section again is all about exercises so we'll look at three examples of code that touches an external resource and finally the last two sections include more challenging exercises I will show you a snippet of source code taken from a real project and your job is to write all the necessary unit tests for that code and of course you're going to see my solution as well so in this section you learned about automated testing and its benefits Maurice pacifically you learned that it helps you prefactor your code with confidence and release software of better quality and with less bugs you learn about three types of tests unit integration and end-to-end tests and you also saw a glimpse of unit testing in action you learn how to write a basic unit test in Visual Studio and finally you learned how to run and debug your unit tests in the next section we're going to look at the core techniques for writing unit tests so I will see you in the next section bye guys maash here so if you made it this far you seem to be really enthusiastic about learning unit testing so I highly recommend you to enroll in my unit testing course and don't waste your time jumping from one tutorial to another when you enroll you will learn everything about unit testing from A to Z and by the end of watching the course you'll also get a certificate of completion which you can present your current or future employers so the link to the full course is in the video description I hope to see in the course
Info
Channel: Programming with Mosh
Views: 406,151
Rating: undefined out of 5
Keywords: unit testing c#, unit testing, c#, .net, mstest, nunit, resharper, .net unit testing, c# unit testing, c# unit test example, visual studio, best practices, mocking, black box testing, unit testing tutorial, code with mosh, programming with mosh, how to write unit tests in c#, create a unit test c#
Id: HYrXogLj7vg
Channel Id: undefined
Length: 44min 55sec (2695 seconds)
Published: Tue Nov 07 2017
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.