{"id":3847,"date":"2018-07-16T07:00:01","date_gmt":"2018-07-16T06:00:01","guid":{"rendered":"https:\/\/code-maze.com\/?p=3847"},"modified":"2024-01-31T15:17:07","modified_gmt":"2024-01-31T14:17:07","slug":"unit-testing-aspnetcore-web-api","status":"publish","type":"post","link":"https:\/\/code-maze.com\/unit-testing-aspnetcore-web-api\/","title":{"rendered":"Unit Testing in ASP.NET Core Web API"},"content":{"rendered":"<p>Software maintenance is an inevitable part of the development process and one that could give developers the most trouble. We\u2019ve all been there, whether we left our code in someone else\u2019s care, or we\u2019ve inherited some legacy code.<\/p>\n<p>This doesn\u2019t necessarily need to be a bad thing and there are ways to improve our code and make it more maintainable. <a href=\"https:\/\/code-maze.com\/asp-net-core-mvc-testing\/\" target=\"_blank\" rel=\"noopener noreferrer\">Unit testing<\/a> plays a very important role in making the software more maintainable.<\/p>\n<p>Our intention in this post is to make an <strong>intro to unit testing of the ASP.NET Core Web API application<\/strong>.<\/p>\n<div style=\"padding: 20px; border-left: 5px #dc2323 solid; display: block; margin-bottom: 20px; box-shadow: 1px 1px 5px 0px lightgrey;\">You can download the source code from <a href=\"https:\/\/github.com\/CodeMazeBlog\/unit-testing-aspnetcore-webapi\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">the repo on GitHub.<\/a><\/div>\n<p>Let&#8217;s start<\/p>\n<h2 id=\"aboutunittesting\">About Unit Testing in General<\/h2>\n<p>What is unit testing in the first place? It begins by defining what a \u201eunit\u201c is and although this is not strictly defined, the unit represents a unit of work &#8211; usually a single method in our code.<\/p>\n<p>We test these units individually, making sure that each of them is doing exactly what it is written for.<\/p>\n<p>Nothing more, nothing less.<\/p>\n<p>What is important to understand is that we are not testing the behavior of the dependencies of that method. That is what the integration tests are for.<\/p>\n<div style=\"padding: 20px; border-left: 5px #dc2323 solid; display: block; margin-bottom: 20px; box-shadow: 1px 1px 5px 0px lightgrey;\"> We have a great series of articles dedicated to Testing ASP.NET Core Application. So, if you want to learn even more about the testing, we strongly recommend reading <a href=\"https:\/\/code-maze.com\/asp-net-core-mvc-testing\/\" target=\"_blank\" rel=\"noopener noreferrer\">ASP.NET Core MVC Testing Series<\/a>.<\/div>\n<h2 id=\"preparingtheproject\"><span lang=\"SR-LATN-RS\">Preparing the Example Project<\/span><\/h2>\n<p>We will use Visual Studio to create our example project and it will be an <a href=\"https:\/\/code-maze.com\/net-core-series\/\" target=\"_blank\" rel=\"noopener noreferrer\">ASP.NET Core Web API<\/a> application.<\/p>\n<p>So, let\u2019s start by creating a new ASP.NET Core Web Application.<\/p>\n<p>When we create the <a href=\"https:\/\/code-maze.com\/net-core-series\/\" target=\"_blank\" rel=\"noopener noreferrer\">ASP.NET Core API<\/a> application initially, it comes with the default controller class.<\/p>\n<p>Let\u2019s delete that one and create our own example controller named <code>ShoppingCartController<\/code>. Here we can define CRUD operations you would typically have on an entity based controller:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\">[Route(\"api\/[controller]\")]\r\n[ApiController]\r\npublic class ShoppingCartController : ControllerBase\r\n{\r\n    private readonly IShoppingCartService _service;\r\n    public ShoppingCartController(IShoppingCartService service)\r\n    {\r\n        _service = service;\r\n    }\r\n\r\n    [HttpGet]\r\n    public IActionResult Get()\r\n    {\r\n        var items = _service.GetAllItems();\r\n        return Ok(items);\r\n    }\r\n\r\n    [HttpGet(\"{id}\")]\r\n    public IActionResult Get(Guid id)\r\n    {\r\n        var item = _service.GetById(id);\r\n        if (item == null)\r\n        {\r\n            return NotFound();\r\n        }\r\n        return Ok(item);\r\n    }\r\n\r\n    [HttpPost]\r\n    public IActionResult Post([FromBody] ShoppingItem value)\r\n    {\r\n        if (!ModelState.IsValid)\r\n        {\r\n            return BadRequest(ModelState);\r\n        }\r\n        var item = _service.Add(value);\r\n        return CreatedAtAction(\"Get\", new { id = item.Id }, item);\r\n    }\r\n\r\n    [HttpDelete(\"{id}\")]\r\n    public IActionResult Remove(Guid id)\r\n    {\r\n        var existingItem = _service.GetById(id);\r\n        if (existingItem == null)\r\n        {\r\n            return NotFound();\r\n        }\r\n        _service.Remove(id);\r\n        return NoContent();\r\n    }\r\n}<\/pre>\n<p>Nothing special about the code here, we\u2019ve got a simple example of a shopping cart controller where we have methods to get, add and remove items from the cart.<\/p>\n<h2 id=\"shopingcartservice\">ShoppingCartService Explanation<\/h2>\n<p>To access the data source, we are using <code>ShoppingService<\/code> class that implements <code>IShoppingService<\/code> interface. This allows us to follow the dependency injection principle, which is used heavily for the purpose of unit testing.<\/p>\n<p>Using dependency injection, we can inject whatever implementation of <code>IShoppingCart<\/code> interface we want into our test class.<\/p>\n<p><em>Please note that methods of the service are not implemented in the example project, because we are not focusing on the service implementation here, testing the controller is the main goal. In the real project, you would probably use some data access logic in your service methods:<\/em><\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\">public class ShoppingCartService : IShoppingCartService\r\n{\r\n    public ShoppingItem Add(ShoppingItem newItem) =&gt; throw new NotImplementedException();\r\n\r\n    public IEnumerable&lt;ShoppingItem&gt; GetAllItems() =&gt; throw new NotImplementedException();\r\n\r\n    public ShoppingItem GetById(Guid id) =&gt; throw new NotImplementedException();\r\n\r\n    public void Remove(Guid id) =&gt; throw new NotImplementedException();\r\n}<\/pre>\n<p><code>IShoppingService<\/code> contains signatures of all the methods seen in the <code>ShoppingCartService<\/code>:<\/p>\n<pre  class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\">public interface IShoppingCartService\r\n{\r\n    IEnumerable&lt;ShoppingItem&gt; GetAllItems();\r\n    ShoppingItem Add(ShoppingItem newItem);\r\n    ShoppingItem GetById(Guid id);\r\n    void Remove(Guid id);\r\n}\r\n<\/pre>\n<p><code>ShoppingItem<\/code> is our main (and only \ud83d\ude42 ) entity with just a few fields:<\/p>\n<pre  class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\">public class ShoppingItem\r\n{\r\n    public Guid Id { get; set; }\r\n    [Required]\r\n    public string Name { get; set; }\r\n    public decimal Price { get; set; }\r\n    public string Manufacturer { get; set; }\r\n}\r\n<\/pre>\n<p>As we are using dependency injection to create instances of our services, make sure not to forget to register the service in the <code>Startup<\/code> class:<\/p>\n<p><code class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\">services.AddScoped&lt;IShoppingCartService, ShoppingCartService&gt;();<\/code><\/p>\n<p>Of course, if you are using .NET 6, you have to use the <code>Program<\/code> class:<\/p>\n<p><code class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\">builder.Services.AddScoped&lt;IShoppingCartService, ShoppingCartService&gt;();<\/code><\/p>\n<h2>Creating a Testing Project<\/h2>\n<p>Finally, we come to the point when we need to create a new project where our tests are going to be. Conveniently for us, there is a <code>xUnit<\/code> testing project template out-of-the-box when using visual studio 2019, so we are going to make use of that.<\/p>\n<p>The <code>xUnit<\/code> is an open-source unit testing tool for the .NET framework that simplifies the testing process and allows us to spend more time focusing on writing our tests:<\/p>\n<p><a href=\"https:\/\/code-maze.com\/wp-content\/uploads\/2018\/07\/new-xunit-project.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-49654 size-full\" src=\"https:\/\/code-maze.com\/wp-content\/uploads\/2018\/07\/new-xunit-project.png\" alt=\"xUnit project - unit testing with .NET Core\" width=\"966\" height=\"322\" srcset=\"https:\/\/code-maze.com\/wp-content\/uploads\/2018\/07\/new-xunit-project.png 966w, https:\/\/code-maze.com\/wp-content\/uploads\/2018\/07\/new-xunit-project-300x100.png 300w, https:\/\/code-maze.com\/wp-content\/uploads\/2018\/07\/new-xunit-project-768x256.png 768w\" sizes=\"auto, (max-width: 966px) 100vw, 966px\" \/><\/a><\/p>\n<p>We are going to name it <code>web-api-tests<\/code>.<\/p>\n<p>Now we have a new project in our solution named <code>web-api-tests<\/code>. The next thing we should do is to add the reference to the project we are about to write tests for:<\/p>\n<p><a href=\"https:\/\/code-maze.com\/wp-content\/uploads\/2018\/07\/referencing-web-api.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-49655 size-full\" src=\"https:\/\/code-maze.com\/wp-content\/uploads\/2018\/07\/referencing-web-api.png\" alt=\"reference project\" width=\"438\" height=\"139\" srcset=\"https:\/\/code-maze.com\/wp-content\/uploads\/2018\/07\/referencing-web-api.png 438w, https:\/\/code-maze.com\/wp-content\/uploads\/2018\/07\/referencing-web-api-300x95.png 300w\" sizes=\"auto, (max-width: 438px) 100vw, 438px\" \/><\/a><\/p>\n<p>At this time we should create our fake implementation of the <code>IShoppingCartService<\/code> interface, which we are going to inject into our controller at the time of testing.<\/p>\n<p>It has an in-memory collection which we are going to fill up with our dummy data:<\/p>\n<pre  class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\">public class ShoppingCartServiceFake: IShoppingCartService\r\n{\r\n    private readonly List&lt;ShoppingItem&gt; _shoppingCart;\r\n\r\n    public ShoppingCartServiceFake()\r\n    {\r\n        _shoppingCart = new List&lt;ShoppingItem&gt;()\r\n            {\r\n                new ShoppingItem() { Id = new Guid(\"ab2bd817-98cd-4cf3-a80a-53ea0cd9c200\"),\r\n                    Name = \"Orange Juice\", Manufacturer=\"Orange Tree\", Price = 5.00M },\r\n                new ShoppingItem() { Id = new Guid(\"815accac-fd5b-478a-a9d6-f171a2f6ae7f\"),\r\n                    Name = \"Diary Milk\", Manufacturer=\"Cow\", Price = 4.00M },\r\n                new ShoppingItem() { Id = new Guid(\"33704c4a-5b87-464c-bfb6-51971b4d18ad\"),\r\n                    Name = \"Frozen Pizza\", Manufacturer=\"Uncle Mickey\", Price = 12.00M }\r\n            };\r\n    }\r\n\r\n    public IEnumerable&lt;ShoppingItem&gt; GetAllItems()\r\n    {\r\n        return _shoppingCart;\r\n    }\r\n\r\n    public ShoppingItem Add(ShoppingItem newItem)\r\n    {\r\n        newItem.Id = Guid.NewGuid();\r\n        _shoppingCart.Add(newItem);\r\n        return newItem;\r\n    }\r\n\r\n    public ShoppingItem GetById(Guid id)\r\n    {\r\n        return _shoppingCart.Where(a =&gt; a.Id == id)\r\n            .FirstOrDefault();\r\n    }\r\n\r\n    public void Remove(Guid id)\r\n    {\r\n        var existing = _shoppingCart.First(a =&gt; a.Id == id);\r\n        _shoppingCart.Remove(existing);\r\n    }\r\n}<\/pre>\n<div style=\"padding: 20px; border-left: 5px #dc2323 solid; display: block; margin-bottom: 20px; box-shadow: 1px 1px 5px 0px lightgrey;\"> Instead of creating a fake service manually, we could\u2019ve used one of the many mocking frameworks available. One of those frameworks is called Moq. You can get more information about it in the <a href=\"https:\/\/code-maze.com\/testing-mvc-controllers-asp-net-core\/\" target=\"_blank\" rel=\"noopener noreferrer\">Testing MVC Controllers<\/a> article, where we use the Moq library to isolate our dependencies.<\/div>\n<h2 id=\"letswritetests\">Let\u2019s write some unit tests!<\/h2>\n<p>Now we are all set and ready to write tests for our first unit of work \u2013 the <code>Get<\/code> method in our <code>ShoppingCartController<\/code>.<\/p>\n<p>We will decorate test methods with the <code>[Fact]<\/code> attribute, which is used by the <code>xUnit<\/code> framework, marking them as the actual testing methods. Besides the test methods, we can have any number of helper methods in the test class as well<em>.<\/em><\/p>\n<p>When writing unit tests it is usually the practice to follow the AAA principle (Arrange, Act, and Assert):<\/p>\n<p><strong>Arrange<\/strong> \u2013 this is where you would typically prepare everything for the test, in other words, prepare the scene for testing (creating the objects and setting them up as necessary)<\/p>\n<p><strong>Act<\/strong> \u2013 this is where the method we are testing is executed<\/p>\n<p><strong>Assert<\/strong> \u2013 this is the final part of the test where we compare what we expect to happen with the actual result of the test method execution<\/p>\n<p>Test method names should be as descriptive as possible. In most cases, it is possible to name the method so that it is not even necessary to read the actual code to understand what is being tested.<\/p>\n<p>In the example we use the naming convention in which the first part represents the name of the method being tested, the second part tells us more about the testing scenario and the last part is the expected result.<\/p>\n<p>Generally, the logic inside our controllers should be minimal and not so focused on business logic or infrastructure (eg. data access). We want to test the controller logic and not the frameworks we are using.<\/p>\n<p>We need to test how the controller behaves based on the validity of the inputs and controller responses based on the result of the operation it performs.<\/p>\n<p><a href=\"https:\/\/code-maze.com\/wp-content\/uploads\/2018\/07\/show-me-the-source-yoda.jpg\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-3846 size-full\" src=\"https:\/\/code-maze.com\/wp-content\/uploads\/2018\/07\/show-me-the-source-yoda.jpg\" alt=\"yoda\" width=\"400\" height=\"400\" srcset=\"https:\/\/code-maze.com\/wp-content\/uploads\/2018\/07\/show-me-the-source-yoda.jpg 400w, https:\/\/code-maze.com\/wp-content\/uploads\/2018\/07\/show-me-the-source-yoda-300x300.jpg 300w, https:\/\/code-maze.com\/wp-content\/uploads\/2018\/07\/show-me-the-source-yoda-100x100.jpg 100w, https:\/\/code-maze.com\/wp-content\/uploads\/2018\/07\/show-me-the-source-yoda-150x150.jpg 150w\" sizes=\"auto, (max-width: 400px) 100vw, 400px\" \/><\/a><\/p>\n<h2 id=\"testingactions\">Testing Our Actions<\/h2>\n<p>The first method we are testing is the <code>Get<\/code> method and there we will want to verify the following:<\/p>\n<ul>\n<li>Whether the method returns the <code>OkObjectResult<\/code> which represents 200 HTTP code response<\/li>\n<li>Whether returned object contains our list of <code>ShoppingItems<\/code> and all of our items<\/li>\n<\/ul>\n<h3><span lang=\"SR-LATN-RS\">Testing the Get Method<\/span><\/h3>\n<p>So let\u2019s see how we go about testing our method:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\">public class ShoppingCartControllerTest\r\n{\r\n    private readonly ShoppingCartController _controller;\r\n    private readonly IShoppingCartService _service;\r\n\r\n    public ShoppingCartControllerTest()\r\n    {\r\n        _service = new ShoppingCartServiceFake();\r\n        _controller = new ShoppingCartController(_service);\r\n    }\r\n\r\n    [Fact]\r\n    public void Get_WhenCalled_ReturnsOkResult()\r\n    {\r\n        \/\/ Act\r\n        var okResult = _controller.Get();\r\n\r\n        \/\/ Assert\r\n        Assert.IsType&lt;OkObjectResult&gt;(okResult as OkObjectResult);\r\n    }\r\n\r\n    [Fact]\r\n    public void Get_WhenCalled_ReturnsAllItems()\r\n    {\r\n        \/\/ Act\r\n        var okResult = _controller.Get() as OkObjectResult;\r\n\r\n        \/\/ Assert\r\n        var items = Assert.IsType&lt;List&lt;ShoppingItem&gt;&gt;(okResult.Value);\r\n        Assert.Equal(3, items.Count);\r\n    }\r\n}<\/pre>\n<p>We create an instance of the <code>ShoppingCartController<\/code> object in the test class and that is the class we want to test. It is important to note here that this constructor is called before each test method, meaning that we are always resetting the controller state and performing the test on the fresh object.<\/p>\n<p>This is important because the test methods should not be dependent on one another and we should get the same testing results, no matter how many times we run the tests and in which order we run them.<\/p>\n<h3><span lang=\"SR-LATN-RS\">Testing the GetById method<\/span><\/h3>\n<p>Now let\u2019s see how we can test the <code>GetById<\/code> method:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\">[Fact]\r\npublic void GetById_UnknownGuidPassed_ReturnsNotFoundResult()\r\n{\r\n    \/\/ Act\r\n    var notFoundResult = _controller.Get(Guid.NewGuid());\r\n\r\n    \/\/ Assert\r\n    Assert.IsType&lt;NotFoundResult&gt;(notFoundResult);\r\n}\r\n\r\n[Fact]\r\npublic void GetById_ExistingGuidPassed_ReturnsOkResult()\r\n{\r\n    \/\/ Arrange\r\n    var testGuid = new Guid(\"ab2bd817-98cd-4cf3-a80a-53ea0cd9c200\");\r\n\r\n    \/\/ Act\r\n    var okResult = _controller.Get(testGuid);\r\n\r\n    \/\/ Assert\r\n    Assert.IsType&lt;OkObjectResult&gt;(okResult as OkObjectResult);\r\n}\r\n\r\n[Fact]\r\npublic void GetById_ExistingGuidPassed_ReturnsRightItem()\r\n{\r\n    \/\/ Arrange\r\n    var testGuid = new Guid(\"ab2bd817-98cd-4cf3-a80a-53ea0cd9c200\");\r\n\r\n    \/\/ Act\r\n    var okResult = _controller.Get(testGuid) as OkObjectResult;\r\n\r\n    \/\/ Assert\r\n    Assert.IsType&lt;ShoppingItem&gt;(okResult.Value);\r\n    Assert.Equal(testGuid, (okResult.Value as ShoppingItem).Id);\r\n}<\/pre>\n<p>Firstly we verify that the controller will return a 404 status code (Not Found) if someone asks for the non-existing <code>ShoppingItem<\/code>. Secondly, we test if 200 code is returned when the existing object is asked for and lastly we check if the right object is returned.<\/p>\n<h3><span lang=\"SR-LATN-RS\">Testing the Add Method<\/span><\/h3>\n<p>Let\u2019s see how we can deal with the Add method:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\">[Fact]\r\npublic void Add_InvalidObjectPassed_ReturnsBadRequest()\r\n{\r\n    \/\/ Arrange\r\n    var nameMissingItem = new ShoppingItem()\r\n    {\r\n        Manufacturer = \"Guinness\",\r\n        Price = 12.00M\r\n    };\r\n    _controller.ModelState.AddModelError(\"Name\", \"Required\");\r\n\r\n    \/\/ Act\r\n    var badResponse = _controller.Post(nameMissingItem);\r\n\r\n    \/\/ Assert\r\n    Assert.IsType&lt;BadRequestObjectResult&gt;(badResponse);\r\n}\r\n\r\n[Fact]\r\npublic void Add_ValidObjectPassed_ReturnsCreatedResponse()\r\n{\r\n    \/\/ Arrange\r\n    ShoppingItem testItem = new ShoppingItem()\r\n    {\r\n        Name = \"Guinness Original 6 Pack\",\r\n        Manufacturer = \"Guinness\",\r\n        Price = 12.00M\r\n    };\r\n\r\n    \/\/ Act\r\n    var createdResponse = _controller.Post(testItem);\r\n\r\n    \/\/ Assert\r\n    Assert.IsType&lt;CreatedAtActionResult&gt;(createdResponse);\r\n}\r\n\r\n[Fact]\r\npublic void Add_ValidObjectPassed_ReturnedResponseHasCreatedItem()\r\n{\r\n    \/\/ Arrange\r\n    var testItem = new ShoppingItem()\r\n    {\r\n        Name = \"Guinness Original 6 Pack\",\r\n        Manufacturer = \"Guinness\",\r\n        Price = 12.00M\r\n    };\r\n\r\n    \/\/ Act\r\n    var createdResponse = _controller.Post(testItem) as CreatedAtActionResult;\r\n    var item = createdResponse.Value as ShoppingItem;\r\n\r\n    \/\/ Assert\r\n    Assert.IsType&lt;ShoppingItem&gt;(item);\r\n    Assert.Equal(\"Guinness Original 6 Pack\", item.Name);\r\n}<\/pre>\n<p>Once again we are testing that the right objects are returned when someone calls the method, but there is something important to note here.<\/p>\n<p>Among other things, we are testing if <code>ModelState<\/code> is validated and the proper response is returned in the case that the model is not valid. But to achieve this, it is not enough to just pass the invalid object to the Add method. That wouldn&#8217;t work anyway since model state validation is only triggered during runtime. It is up to integration tests to check if the model binding works properly.<\/p>\n<p>What we are going to do here instead is add the <code>ModelError<\/code> object explicitly to the <code>ModelState<\/code> and then assert on the response of the called method.<\/p>\n<h3><span lang=\"SR-LATN-RS\">Remove method<\/span><\/h3>\n<p>Testing the remove method is pretty straightforward:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\">[Fact]\r\npublic void Remove_NotExistingGuidPassed_ReturnsNotFoundResponse()\r\n{\r\n    \/\/ Arrange\r\n    var notExistingGuid = Guid.NewGuid();\r\n\r\n    \/\/ Act\r\n    var badResponse = _controller.Remove(notExistingGuid);\r\n\r\n    \/\/ Assert\r\n    Assert.IsType&lt;NotFoundResult&gt;(badResponse);\r\n}\r\n\r\n[Fact]\r\npublic void Remove_ExistingGuidPassed_ReturnsNoContentResult()\r\n{\r\n    \/\/ Arrange\r\n    var existingGuid = new Guid(\"ab2bd817-98cd-4cf3-a80a-53ea0cd9c200\");\r\n\r\n    \/\/ Act\r\n    var noContentResponse = _controller.Remove(existingGuid);\r\n\r\n    \/\/ Assert\r\n    Assert.IsType&lt;NoContentResult&gt;(noContentResponse);\r\n}\r\n\r\n[Fact]\r\npublic void Remove_ExistingGuidPassed_RemovesOneItem()\r\n{\r\n    \/\/ Arrange\r\n    var existingGuid = new Guid(\"ab2bd817-98cd-4cf3-a80a-53ea0cd9c200\");\r\n\r\n    \/\/ Act\r\n    var okResponse = _controller.Remove(existingGuid);\r\n\r\n    \/\/ Assert\r\n    Assert.Equal(2, _service.GetAllItems().Count());\r\n}<\/pre>\n<p>Remove method tests take care that a valid response is returned and that object is indeed removed from the list.<\/p>\n<h2 id=\"summary\"><span lang=\"SR-LATN-RS\">Summary<\/span><\/h2>\n<p>This concludes the tests scenarios for our <code>ShoppingCartController<\/code> and we just want to summarize the general advice about unit testing. There are a few guidelines or best practices you should strive for when writing unit tests. Respecting these practices will certainly make your (and the life of your fellow developer) easier.<\/p>\n<h3><strong>Unit tests should be readable<\/strong><\/h3>\n<p>No one wants to spend time trying to figure out what is that your test does. Ideally, this should be clear just by looking at the test name.<\/p>\n<h3><strong>Unit tests should be maintainable<\/strong><\/h3>\n<p>We should try to write our tests in a way that minor changes to the code shouldn&#8217;t make us change all of our tests. The DRY (don&#8217;t repeat yourself) principle applies here, and we should treat our test code the same as the production code. This lowers the possibility that one day someone gets to the point where he\/she needs to comment out all of our tests because it has become too difficult to maintain them.<\/p>\n<h3><strong>Unit sets should be fast<\/strong><\/h3>\n<p>If tests are taking too long to execute, it is probable that people will run them less often. That is certainly a bad thing and no one wishes to wait too long for tests to execute.<\/p>\n<h3><strong>Unit tests should not have any dependencies<\/strong><\/h3>\n<p>It is important that anyone who is working on the project can execute tests without the need to provide access to some external system or database. Tests need to run in full isolation.<\/p>\n<h3><strong>Make tests trustworthy rather than just aiming for the code coverage<\/strong><\/h3>\n<p>Good tests should provide us with the confidence that we will be able to detect errors before they reach production. It is easy to write tests that don\u2019t assert the right things just to make them pass and to increase code coverage. But there is no point in doing that. We should try to test the right things to be able to rely on them when the time comes to make some changes to the code.<\/p>\n<h2 id=\"conclusion\"><span lang=\"SR-LATN-RS\">Conclusion<\/span><\/h2>\n<p>In this post, we\u2019ve learned what unit testing is and how to set up the unit testing project with xUnit.<\/p>\n<p>We\u2019ve also learned the basic scenarios of testing the controller logic on some CRUD operations.<\/p>\n<p>These examples should give you a great starting point for writing your own unit tests, and testing the more complex projects.<\/p>\n<p>Thanks for reading and hopefully this article will help you grasp the unit concepts and unit testing in ASP.NET Core a little bit better.<\/p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Software maintenance is an inevitable part of the development process and one that could give developers the most trouble. We\u2019ve all been there, whether we left our code in someone else\u2019s care, or we\u2019ve inherited some legacy code. This doesn\u2019t necessarily need to be a bad thing and there are ways to improve our code [&hellip;]<\/p>\n","protected":false},"author":6,"featured_media":54965,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_et_pb_use_builder":"","_et_pb_old_content":"","_et_gb_content_width":"","footnotes":""},"categories":[12,2079],"tags":[180,179,79,176,177,174,178,173],"class_list":["post-3847","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-csharp","category-web-api","tag-act","tag-arrange","tag-asp-net-core","tag-assert","tag-fact","tag-test-in-net-core","tag-unit","tag-unit-testing","et-has-post-format-content","et_post_format-et-post-format-standard"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v24.7 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Unit Testing in ASP.NET Core Web API - Code Maze Blog<\/title>\n<meta name=\"description\" content=\"Find out what Unit testing is and how to write unit tests in ASP.NET Core Web API Project to test Controllers and Repo logic.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/code-maze.com\/unit-testing-aspnetcore-web-api\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Unit Testing in ASP.NET Core Web API - Code Maze Blog\" \/>\n<meta property=\"og:description\" content=\"Find out what Unit testing is and how to write unit tests in ASP.NET Core Web API Project to test Controllers and Repo logic.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/code-maze.com\/unit-testing-aspnetcore-web-api\/\" \/>\n<meta property=\"og:site_name\" content=\"Code Maze\" \/>\n<meta property=\"article:published_time\" content=\"2018-07-16T06:00:01+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2024-01-31T14:17:07+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/code-maze.com\/wp-content\/uploads\/2018\/07\/unit-testing.png\" \/>\n\t<meta property=\"og:image:width\" content=\"1100\" \/>\n\t<meta property=\"og:image:height\" content=\"620\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"author\" content=\"Code Maze\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@https:\/\/twitter.com\/CodeMazeBlog\" \/>\n<meta name=\"twitter:site\" content=\"@CodeMazeBlog\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Code Maze\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"12 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":[\"Article\",\"BlogPosting\"],\"@id\":\"https:\/\/code-maze.com\/unit-testing-aspnetcore-web-api\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/code-maze.com\/unit-testing-aspnetcore-web-api\/\"},\"author\":{\"name\":\"Code Maze\",\"@id\":\"https:\/\/code-maze.com\/#\/schema\/person\/09d29b223012c8e94a68ba62861d0b04\"},\"headline\":\"Unit Testing in ASP.NET Core Web API\",\"datePublished\":\"2018-07-16T06:00:01+00:00\",\"dateModified\":\"2024-01-31T14:17:07+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/code-maze.com\/unit-testing-aspnetcore-web-api\/\"},\"wordCount\":1804,\"commentCount\":19,\"publisher\":{\"@id\":\"https:\/\/code-maze.com\/#organization\"},\"image\":{\"@id\":\"https:\/\/code-maze.com\/unit-testing-aspnetcore-web-api\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/code-maze.com\/wp-content\/uploads\/2018\/07\/unit-testing.png\",\"keywords\":[\"act\",\"arrange\",\"asp.net core\",\"assert\",\"fact\",\"Test in .NET Core\",\"unit\",\"Unit Testing\"],\"articleSection\":[\"C#\",\"Web API\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/code-maze.com\/unit-testing-aspnetcore-web-api\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/code-maze.com\/unit-testing-aspnetcore-web-api\/\",\"url\":\"https:\/\/code-maze.com\/unit-testing-aspnetcore-web-api\/\",\"name\":\"Unit Testing in ASP.NET Core Web API - Code Maze Blog\",\"isPartOf\":{\"@id\":\"https:\/\/code-maze.com\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/code-maze.com\/unit-testing-aspnetcore-web-api\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/code-maze.com\/unit-testing-aspnetcore-web-api\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/code-maze.com\/wp-content\/uploads\/2018\/07\/unit-testing.png\",\"datePublished\":\"2018-07-16T06:00:01+00:00\",\"dateModified\":\"2024-01-31T14:17:07+00:00\",\"description\":\"Find out what Unit testing is and how to write unit tests in ASP.NET Core Web API Project to test Controllers and Repo logic.\",\"breadcrumb\":{\"@id\":\"https:\/\/code-maze.com\/unit-testing-aspnetcore-web-api\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/code-maze.com\/unit-testing-aspnetcore-web-api\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/code-maze.com\/unit-testing-aspnetcore-web-api\/#primaryimage\",\"url\":\"https:\/\/code-maze.com\/wp-content\/uploads\/2018\/07\/unit-testing.png\",\"contentUrl\":\"https:\/\/code-maze.com\/wp-content\/uploads\/2018\/07\/unit-testing.png\",\"width\":1100,\"height\":620,\"caption\":\"unit testing\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/code-maze.com\/unit-testing-aspnetcore-web-api\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/code-maze.com\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Unit Testing in ASP.NET Core Web API\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/code-maze.com\/#website\",\"url\":\"https:\/\/code-maze.com\/\",\"name\":\"Code Maze\",\"description\":\"Learn. Code. Succeed.\",\"publisher\":{\"@id\":\"https:\/\/code-maze.com\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/code-maze.com\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/code-maze.com\/#organization\",\"name\":\"Code Maze\",\"url\":\"https:\/\/code-maze.com\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/code-maze.com\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/code-maze.com\/wp-content\/uploads\/2020\/01\/Code-Maze-Only-Logo-Transparent-HRez.png\",\"contentUrl\":\"https:\/\/code-maze.com\/wp-content\/uploads\/2020\/01\/Code-Maze-Only-Logo-Transparent-HRez.png\",\"width\":3511,\"height\":3510,\"caption\":\"Code Maze\"},\"image\":{\"@id\":\"https:\/\/code-maze.com\/#\/schema\/logo\/image\/\"},\"sameAs\":[\"https:\/\/x.com\/CodeMazeBlog\"]},{\"@type\":\"Person\",\"@id\":\"https:\/\/code-maze.com\/#\/schema\/person\/09d29b223012c8e94a68ba62861d0b04\",\"name\":\"Code Maze\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/code-maze.com\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/code-maze.com\/wp-content\/uploads\/2020\/01\/Code-Maze-Only-Logo-Transparent-HRez-150x150.png\",\"contentUrl\":\"https:\/\/code-maze.com\/wp-content\/uploads\/2020\/01\/Code-Maze-Only-Logo-Transparent-HRez-150x150.png\",\"caption\":\"Code Maze\"},\"description\":\"This is the standard author on the site. Most articles are published by individual authors, with their profiles, but when several authors have contributed, we publish collectively as a part of this profile.\",\"sameAs\":[\"https:\/\/www.linkedin.com\/company\/codemaze\/\",\"https:\/\/x.com\/https:\/\/twitter.com\/CodeMazeBlog\"],\"url\":\"https:\/\/code-maze.com\/author\/codemazecontributor\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Unit Testing in ASP.NET Core Web API - Code Maze Blog","description":"Find out what Unit testing is and how to write unit tests in ASP.NET Core Web API Project to test Controllers and Repo logic.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/code-maze.com\/unit-testing-aspnetcore-web-api\/","og_locale":"en_US","og_type":"article","og_title":"Unit Testing in ASP.NET Core Web API - Code Maze Blog","og_description":"Find out what Unit testing is and how to write unit tests in ASP.NET Core Web API Project to test Controllers and Repo logic.","og_url":"https:\/\/code-maze.com\/unit-testing-aspnetcore-web-api\/","og_site_name":"Code Maze","article_published_time":"2018-07-16T06:00:01+00:00","article_modified_time":"2024-01-31T14:17:07+00:00","og_image":[{"width":1100,"height":620,"url":"https:\/\/code-maze.com\/wp-content\/uploads\/2018\/07\/unit-testing.png","type":"image\/png"}],"author":"Code Maze","twitter_card":"summary_large_image","twitter_creator":"@https:\/\/twitter.com\/CodeMazeBlog","twitter_site":"@CodeMazeBlog","twitter_misc":{"Written by":"Code Maze","Est. reading time":"12 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":["Article","BlogPosting"],"@id":"https:\/\/code-maze.com\/unit-testing-aspnetcore-web-api\/#article","isPartOf":{"@id":"https:\/\/code-maze.com\/unit-testing-aspnetcore-web-api\/"},"author":{"name":"Code Maze","@id":"https:\/\/code-maze.com\/#\/schema\/person\/09d29b223012c8e94a68ba62861d0b04"},"headline":"Unit Testing in ASP.NET Core Web API","datePublished":"2018-07-16T06:00:01+00:00","dateModified":"2024-01-31T14:17:07+00:00","mainEntityOfPage":{"@id":"https:\/\/code-maze.com\/unit-testing-aspnetcore-web-api\/"},"wordCount":1804,"commentCount":19,"publisher":{"@id":"https:\/\/code-maze.com\/#organization"},"image":{"@id":"https:\/\/code-maze.com\/unit-testing-aspnetcore-web-api\/#primaryimage"},"thumbnailUrl":"https:\/\/code-maze.com\/wp-content\/uploads\/2018\/07\/unit-testing.png","keywords":["act","arrange","asp.net core","assert","fact","Test in .NET Core","unit","Unit Testing"],"articleSection":["C#","Web API"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/code-maze.com\/unit-testing-aspnetcore-web-api\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/code-maze.com\/unit-testing-aspnetcore-web-api\/","url":"https:\/\/code-maze.com\/unit-testing-aspnetcore-web-api\/","name":"Unit Testing in ASP.NET Core Web API - Code Maze Blog","isPartOf":{"@id":"https:\/\/code-maze.com\/#website"},"primaryImageOfPage":{"@id":"https:\/\/code-maze.com\/unit-testing-aspnetcore-web-api\/#primaryimage"},"image":{"@id":"https:\/\/code-maze.com\/unit-testing-aspnetcore-web-api\/#primaryimage"},"thumbnailUrl":"https:\/\/code-maze.com\/wp-content\/uploads\/2018\/07\/unit-testing.png","datePublished":"2018-07-16T06:00:01+00:00","dateModified":"2024-01-31T14:17:07+00:00","description":"Find out what Unit testing is and how to write unit tests in ASP.NET Core Web API Project to test Controllers and Repo logic.","breadcrumb":{"@id":"https:\/\/code-maze.com\/unit-testing-aspnetcore-web-api\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/code-maze.com\/unit-testing-aspnetcore-web-api\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/code-maze.com\/unit-testing-aspnetcore-web-api\/#primaryimage","url":"https:\/\/code-maze.com\/wp-content\/uploads\/2018\/07\/unit-testing.png","contentUrl":"https:\/\/code-maze.com\/wp-content\/uploads\/2018\/07\/unit-testing.png","width":1100,"height":620,"caption":"unit testing"},{"@type":"BreadcrumbList","@id":"https:\/\/code-maze.com\/unit-testing-aspnetcore-web-api\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/code-maze.com\/"},{"@type":"ListItem","position":2,"name":"Unit Testing in ASP.NET Core Web API"}]},{"@type":"WebSite","@id":"https:\/\/code-maze.com\/#website","url":"https:\/\/code-maze.com\/","name":"Code Maze","description":"Learn. Code. Succeed.","publisher":{"@id":"https:\/\/code-maze.com\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/code-maze.com\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/code-maze.com\/#organization","name":"Code Maze","url":"https:\/\/code-maze.com\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/code-maze.com\/#\/schema\/logo\/image\/","url":"https:\/\/code-maze.com\/wp-content\/uploads\/2020\/01\/Code-Maze-Only-Logo-Transparent-HRez.png","contentUrl":"https:\/\/code-maze.com\/wp-content\/uploads\/2020\/01\/Code-Maze-Only-Logo-Transparent-HRez.png","width":3511,"height":3510,"caption":"Code Maze"},"image":{"@id":"https:\/\/code-maze.com\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/x.com\/CodeMazeBlog"]},{"@type":"Person","@id":"https:\/\/code-maze.com\/#\/schema\/person\/09d29b223012c8e94a68ba62861d0b04","name":"Code Maze","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/code-maze.com\/#\/schema\/person\/image\/","url":"https:\/\/code-maze.com\/wp-content\/uploads\/2020\/01\/Code-Maze-Only-Logo-Transparent-HRez-150x150.png","contentUrl":"https:\/\/code-maze.com\/wp-content\/uploads\/2020\/01\/Code-Maze-Only-Logo-Transparent-HRez-150x150.png","caption":"Code Maze"},"description":"This is the standard author on the site. Most articles are published by individual authors, with their profiles, but when several authors have contributed, we publish collectively as a part of this profile.","sameAs":["https:\/\/www.linkedin.com\/company\/codemaze\/","https:\/\/x.com\/https:\/\/twitter.com\/CodeMazeBlog"],"url":"https:\/\/code-maze.com\/author\/codemazecontributor\/"}]}},"_links":{"self":[{"href":"https:\/\/code-maze.com\/wp-json\/wp\/v2\/posts\/3847","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/code-maze.com\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/code-maze.com\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/code-maze.com\/wp-json\/wp\/v2\/users\/6"}],"replies":[{"embeddable":true,"href":"https:\/\/code-maze.com\/wp-json\/wp\/v2\/comments?post=3847"}],"version-history":[{"count":5,"href":"https:\/\/code-maze.com\/wp-json\/wp\/v2\/posts\/3847\/revisions"}],"predecessor-version":[{"id":70706,"href":"https:\/\/code-maze.com\/wp-json\/wp\/v2\/posts\/3847\/revisions\/70706"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/code-maze.com\/wp-json\/wp\/v2\/media\/54965"}],"wp:attachment":[{"href":"https:\/\/code-maze.com\/wp-json\/wp\/v2\/media?parent=3847"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/code-maze.com\/wp-json\/wp\/v2\/categories?post=3847"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/code-maze.com\/wp-json\/wp\/v2\/tags?post=3847"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}