.NET Web API Clean Architecture - Key Features

  • Fluent Validation

  • Nswag With .NET Core

  • Call an external WCF Sevice

  • Consume RESTFull API

  • Integration test cases

  • Automation test cases

  • Functional Test cases

  • Performance and Load Testing

  • Redis caching

  • Azure Cosmos DB

  • JWT Token Authentication

  • JWT Refresh Token

  • JWT Authorization

  • Azure Blob storage

  • Azure Portal Access

  • Azure DevOps Access

  • Unit Testing and Code Coverage

  • Source Code Analysis

Lab-8: Unit Testing in ASP.NET Core Web API | Clean Architecture | Microservices Architecture


Table of Contents

  • Introduction
    • What is TDD?
    • What is Unit testing?
    • What is Integration testing?
    • What is Functional testing?
    • Load Tests
  • Projects Setup
    • Adding Projects for Unit Testing
    • Adding Project Reference
    • Adding Files for Test cases
  • Unit Testing Frameworks
    • xUnit
    • Moq
    • AutoFixture
    • Fluent Assertions
    • Unit Testing IDEs
  • Unit Testing Controllers in ASP.NET Core Web API
    • Create Test cases for API project
    • Create Test cases for Core project
    • Create Test cases for Infrastructure Project
    • How to Debug Test Methods with Breakpoints
    • Running the Test in Test Explorer
  • Best practices
    • Benefits of Unit tests
    • Characteristics of a good unit test
    • Naming conventions
    • Code Coverage
  • Continuous Integration
    • Running tests cases in Azure DevOps Pipeline
  • Additional resources

Introduction

Code coverage is always associated with high quality of the code, high quality of the code comes with unit test cases, in this course we will learn how to write effective unit test cases in .NET 6 Web API and build high quality REST APIs. This course will help you to understand how to write 100s unique unit test cases and automate them in Azure CI & CD pipeline; you will also learn on how to use best .NET unit testing frameworks like xUnit, Moq, Autofixure and FluentAssertion for your enterprise level microservices in clear architecture pattern and strictly following Microsoft Unit testing best practices.

What is TDD?

Test Driven Development (TDD) is the approach to write a test before implementing the target code. Here, a test is written that is known to fail, the developer then writes the target code and keeps on updating it so that it passes the test. You should follow TDD approach when creating application.

What is Unit testing?

  • Unit tests ensure that individual components of the application work as expected.
  • Unit tests involve testing a part of an app in isolation from its infrastructure and dependencies.
  • When unit testing controller logic, only the contents of a single action are tested, not the behavior of its dependencies or of the framework itself.
  • Unit tests do not detect issues in the interaction between components—that is the purpose of integration testing.
  • Unit tests are generally simple to write and quick to run. A well-written set of unit tests can be run frequently without much overhead.
  • Unit tests are implemented based on test frameworks like xUnit.net, MSTest, Moq, or NUnit. For the icodeforu.com sample application, we are using xUnit.
  • Unit tests use fakes or mock objects

What is Integration testing?

  • Integration tests ensure that component interactions work as expected against external artifacts like

    • Databases,
    • File System,
    • Network Applications (send emails etc..)
    • Request-Response pipeline
  • ASP.NET Core includes a built-in test web host that can be used to handle HTTP requests without network overhead, meaning that you can run those tests faster than when using a real web host. The test web host (TestServer) is available in a NuGet component as Microsoft.AspNetCore.TestHost. It can be added to integration test projects and used to host ASP.NET Core applications.

  • Purpose of integration tests is to confirm that the system works as expected with these systems, so for integration testing you do not use fakes or mock objects. Instead, you include the infrastructure, like database access or service invocation from other services.

  • Don't write integration tests for every possible permutation of data and file access with databases and file systems.

  • Because integration tests exercise larger segments of code than unit tests, and because integration tests rely on infrastructure elements, they tend to be orders of magnitude slower than unit tests. Thus, it is a good idea to limit how many integration tests you write and run.

Integration tests follow a sequence of events:

  1. The SUT's web host is configured.
  2. A test server client is created to submit requests to the app.
  3. The Arrange test step is executed: The test app prepares a request.
  4. The Act test step is executed: The client submits the request and receives the response.
  5. The Assert test step is executed: The actual response is validated as a pass or fail based on an expected response.
  6. The process continues until all the tests are executed.
  7. The test results are reported.

What is Functional testing?

These tests ensure that the application works as expected from the user's perspective. May interact with dependencies

References:

the-difference-between-unit-integration-and-functional-testing

Load Tests

A load test aims to determine whether or not a system can handle a specified load.

Load tests: Test whether the application can handle a specified load of users for a certain scenario while still satisfying the response goal. The app is run under normal conditions.

Stress tests: Test the Application stability when running under extreme conditions, often for a long period of time. The tests place high user load, either spikes or gradually increasing load, on the app, or they limit the app's computing resources.

Stress tests determine if an app under stress can recover from failure and gracefully return to expected behavior. Under stress, the app isn't run under normal conditions.

Visual Studio 2019 announced plans to deprecate the load testing. The corresponding Azure DevOps cloud-based load testing service has been closed.

The following list contains third-party web performance tools with various feature sets:

  1. Apache JMeter
  2. ApacheBench (ab)
  3. Gatling
  4. k6
  5. Locust
  6. West Wind WebSurge
  7. Netling
  8. Vegeta
  9. NBomber

References:

https://docs.microsoft.com/en-us/aspnet/core/test/load-tests?view=aspnetcore-5.0

Projects Setup

demo

Adding Projects for Unit Testing

Demo

Adding Project Reference

Demo

  • Xunit
  • xunit.runner.visualstudio
  • Microsoft.NET.Test.Sdk

Adding Files for Test cases

DemoUnit Testing Frameworks

xUnit: is a free, open source, community-focused unit testing tool for .NET. Written by the original inventor of NUnit v2. ‘x’ stands for the programming language,

NUnit: is a unit-testing framework for all .NET languages.

MSTest is the default test framework that is shipped along with Visual Studio supports for all .NET languages. The initial version of MSTest (V1) was not open-source; however, MSTest V2 is open-source

xUnit

xUnit use the 3 attributes to create and perform unit tests.

xUnit uses the [Fact] attribute to denote a parameterless unit test,

In contrast, the [Theory] attribute denotes a parameterised test that is true for a subset of data. That data can be supplied in a number of ways, but the most common is with an [InlineData] attribute.

public class CalculatorTests
{
    [Fact]
    public void CanAdd()
    {
        var calculator = new Calculator();

        int value1 = 1;
        int value2 = 2;

        var result = calculator.Add(value1, value2);

        Assert.Equal(3, result);
    }
}

[Theory]
[InlineData(1, 2, 3)]
[InlineData(-4, -6, -10)]
[InlineData(-2, 2, 0)]
[InlineData(int.MinValue, -1, int.MaxValue)]
public void CanAddTheory(int value1, int value2, int expected)
{
	var calculator = new Calculator();

	var result = calculator.Add(value1, value2);

	Assert.Equal(expected, result);
}

3 logical part of the unit test

Each test method normally consists of 3 logical parts,

  1. Arrange - prepare the data which will be required for testing. For example, data used for testing scenarios along with the expected result.

  2. Act- call the method which is being tested making use of the data prepared in the Arrange. Here it will return us the actual result.

  3. Assert - Compare expected results with actual results to decide if the test passed or failed.

Moq

The most popular and friendly mocking framework for .NET

Moq open source library to isolate application code from dependencies for testing.

Moq is a mocking framework for C#/.NET. It is used in unit testing to isolate your class under test from its dependencies and ensure that the proper methods on the dependent objects are being called.

Other mocking frameworks (for .NET) include JustMock, TypeMock, RhinoMocks, nMock, .etc.

You can use Moq to create mock objects that simulate or mimic a real object. Moq can be used to mock both classes and interfaces. However, there are a few limitations you should be aware of. The classes to be mocked can’t be static or sealed,

The first step in using Moq is to install it so that you can use it in your unit test project.

Reference:

https://github.com/moq

AutoFixture

AutoFixture is an open source framework for . NET designed to minimize the 'Arrange' phase of your unit tests. Its primary goal is to allow developers to focus on what is being tested rather than how to setup the test scenario, by making it easier to create object graphs containing test data

AutoFixture allows to remove the need for hand-coding anonymous variables as part of a test’s Arrange phase:

AutoFixture offers integration with xUnit and NUnit making your unit tests even more concise:

AutoFixture also provides integration with popular mocking libraries (NSubstitute, Moq, FakeItEasy).

  • Auto mocking of dependencies and object graphs.
  • Test data generators.

References:

  • https://github.com/AutoFixture/AutoFixture
  • https://autofixture.github.io/

What is AutoFixture AutoMoq?

AutoFixture.AutoMoq is an extension that turns AutoFixture into an Auto-Mocking Container using the Moq dynamic mock library.

There's also a similar extension for AutoFixture that enables auto-mocking with Rhino Mocks.

References:

https://blog.ploeh.dk/2010/08/19/AutoFixtureasanauto-mockingcontainer/

Fluent Assertions

With Fluent Assertions, the assertions look beautiful, natural and, most importantly, extremely readable.

Fluent Assertions is a set of . NET extension methods that allow you to more naturally specify the expected outcome of a TDD or BDD-style unit test.

References:

https://fluentassertions.com/

Unit Testing IDEs

References:

https://visualstudio.microsoft.com/vs/features/testing-tools/

  • Visual Studio
  • Visual Studio for Mac
  • Visual Studio Code

Unit Testing Controllers in ASP.NET Core Web API

Create Test cases for API project

Demo

Create Test cases for Core project

Demo

Create Test cases for Infrastructure Project

References:

https://dejanstojanovic.net/aspnet/2019/september/unit-testing-repositories-in-aspnet-core-with-xunit-and-moq/ https://kenbonny.net/injecting-automapper-profiles-in-tests https://docs.microsoft.com/en-us/ef/ef6/fundamentals/testing/mocking?redirectedfrom=MSDN

How to Debug Test Methods with Breakpoints

Demo

Running the Test in Test Explorer

Demo

Best Practices

Benefits of Unit tests

Less time performing functional tests

Unit tests, on the other hand, take milliseconds, can be run at the press of a button, and don't necessarily require any knowledge of the system at large. Whether or not the test passes or fails is up to the test runner, not the individual.

Protection against regression

Regression defects are defects that are introduced when a change is made to the application. With unit testing, it's possible to rerun your entire suite of tests after every build or even after you change a line of code. Giving you confidence that your new code does not break existing functionality.

Executable documentation

When you have a suite of well-named unit tests, each test should be able to clearly explain the expected output for a given input. In addition, it should be able to verify that it actually works.

Less coupled code

When code is tightly coupled, it can be difficult to unit test. Without creating unit tests for the code that you're writing, coupling may be less apparent. Writing tests for your code will naturally decouple your code, because it would be more difficult to test otherwise.

Characteristics of a good unit test

  • Fast. It is not uncommon for mature projects to have thousands of unit tests. Unit tests should take very little time to run. Milliseconds.
  • Isolated. Unit tests are standalone, can be run in isolation, and have no dependencies on any outside factors such as a file system or database.
  • Repeatable. Running a unit test should be consistent with its results, that is, it always returns the same result if you do not change anything in between runs.
  • Self-Checking. The test should be able to automatically detect if it passed or failed without any human interaction.
  • Timely. A unit test should not take a disproportionately long time to write compared to the code being tested. If you find testing the code taking a large amount of time compared to writing the code, consider a design that is more testable.

Naming Conventions The name of your test should consist of three parts: • The name of the method being tested. • The scenario under which it's being tested. • The expected behavior when the scenario is invoked. Code Coverage Code coverage is a measurement of the amount of code that is run by unit tests - either lines, branches, or methods. A high code coverage percentage is often associated with a higher quality of code.

Continuous Integration

Demo

Running tests cases in Azure DevOps Pipeline

Demo

Additional resources

Testing in .NET https://docs.microsoft.com/en-us/dotnet/core/testing/?WT.mc_id=-blog-shchowd https://docs.microsoft.com/en-us/visualstudio/test/unit-test-basics?view=vs-2019

Steve Smith. Testing controllers https://docs.microsoft.com/aspnet/core/mvc/controllers/testing

Steve Smith. Integration testing https://docs.microsoft.com/aspnet/core/test/integration-tests

Unit testing in .NET using dotnet test https://docs.microsoft.com/dotnet/core/testing/unit-testing-with-dotnet-test

xUnit.net. Official site. https://xunit.net/

Moq. GitHub repo. https://github.com/moq/moq https://github.com/Moq/moq4/wiki/Quickstart

NUnit. Official site. https://nunit.org/

AutoFixure https://www.pluralsight.com/courses/autofixture-dotnet-unit-test-get-started https://github.com/AutoFixture/AutoFixture/wiki/Cheat-Sheet https://github.com/AutoFixture https://app.pluralsight.com/course-player?clipId=0a10c142-b4f3-4fe8-ad68-7ed7117f2b2a https://app.pluralsight.com/library/courses/autofixture-dotnet-unit-test-get-started/table-of-contents

An Introduction to XUnit, Moq and AutoFixture https://engineering.thetrainline.com/an-introduction-to-xunit-moq-and-autofixture-995315f656f

Fluent Assertions https://fluentassertions.com/tips/ Azure Test plan Azure DevOps Test Plans | Test Suites | Parameter Values | Configurations | Shared Steps | Grid View

Integrating SpecFlow with Azure DevOps Integrating SpecFlow with Azure DevOps

Running Tests in Parallel > xUnit.net: https://xunit.net/docs/running-tests-in-parallel

Mocks Aren’t Stubs https://martinfowler.com/articles/mocksArentStubs.html

An error has occurred. This application may no longer respond until reloaded. Reload 🗙