Learn Test-Driven Development with Integration Tests in .NET 5.0
Tags: testing, beginners, codenewbie, dotnet
Published: 2021-04-14 18:00:20

<!-- wp:paragraph -->
<p>TDD (Test Driven Development) is a much debated word in the tech industry. Debates like <em>Whether you should do TDD or not?</em> or <em>How advantageous is it?</em>  are quite popular. Simply said, TDD is write tests before you develop. </p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Now, there are a lot of school of thoughts regarding what type of test's are included and what are not in TDD. As an example, should it include Unit Test, Integration Test, System Test or even UAT? </p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>In this article, we will go through a real-world example on how to write integration tests in .NET 5.0 with TDD methodology.</p>
<!-- /wp:paragraph -->

<!-- wp:heading -->
<h2>Project Requirements</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>TDD requires a very clear understanding of scope of work. Without clarity, all the test cases might not be covered.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Let's define the scope of work. We will be developing a <em>patient admission system</em> for a Hospital.</p>
<!-- /wp:paragraph -->

<!-- wp:heading {"level":4} -->
<h4>Business Requirements</h4>
<!-- /wp:heading -->

<!-- wp:list -->
<ul><li>A hospital has X ICU rooms, Y Premium rooms &amp; Z General rooms.</li><li>ICU &amp; Premium rooms can have a single patient at a time, while General rooms can have 2 patients. Each room has a room number.</li><li>On admitting, the patient has to provide name, age, gender &amp; phone number. </li><li>It is possible to search a patient via name or phone number.</li><li>Same patient cannot be admitted to multiple beds while he is still checked in.</li><li>A patient cannot be admitted if all the rooms are occupied.</li></ul>
<!-- /wp:list -->

<!-- wp:heading {"level":4} -->
<h4>Model Validation Rules</h4>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Based on the above requirements, there are 2 models namely Patient &amp; Room. </p>
<!-- /wp:paragraph -->

<!-- wp:list -->
<ul><li>A patient's age is between 0 &amp; 150. The length of name should be between 2 and 40. Gender can be male, female &amp; other. Phone Number's length should be between 7 and 12 and it should all be digits. </li><li>Room type can be either "ICU", "Premium" or "General".</li></ul>
<!-- /wp:list -->

<!-- wp:heading {"level":4} -->
<h4>Test Cases</h4>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Now, that we have defined rules &amp; requirements, lets start creating test cases. Since it's a basic CRUD application we mostly have integration tests. </p>
<!-- /wp:paragraph -->

<!-- wp:heading {"level":6} -->
<h6>Patient</h6>
<!-- /wp:heading -->

<!-- wp:list -->
<ul><li>Do all the model validation tests.</li><li>Admit the same patient twice</li><li>Check out the same patient twice. </li><li>Admit the same patient to multiple rooms at the same time.</li><li>Search a patient with phone number and name.</li></ul>
<!-- /wp:list -->

<!-- wp:heading -->
<h2>TDD Setup</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>In the above section we gathered requirements. Secondly, we defined the models. Finally, we created the list of test cases which we will implement. </p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Open your terminal and run the below script to create and setup a new project.</p>
<!-- /wp:paragraph -->

```
mkdir TDD
cd TDD
dotnet new sln
dotnet new webapi --name TDD
dotnet new xunit --name TDD.Tests
cd TDD
dotnet add package Microsoft.EntityFrameworkCore --version 5.0.5
cd ../TDD.Tests
dotnet add reference ../TDD/TDD.csproj
dotnet add package Microsoft.EntityFrameworkCore --version 5.0.5
dotnet add package Microsoft.AspNetCore.Hosting --version 2.2.7
dotnet add package Microsoft.AspNetCore.Mvc.Testing --version 5.0.5
dotnet add package Microsoft.EntityFrameworkCore.InMemory --version 5.0.5
cd ..
dotnet sln add TDD/TDD.csproj
dotnet sln add TDD.Tests/TDD.Tests.csproj
code .
```
<!-- wp:paragraph -->
<p>The above script creates a solution file named <em>TDD.sln</em>. Secondly, we create 2 projects for TDD &amp; TDD.Tests. Then we add the dependencies for each project. Lastly, we add the projects to the solution and open the project in VS Code. </p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Before we start testing, some more setup is required. Basically, integration tests test the a specific module without mocking. So we will be mimicking our application via TestServer.</p>
<!-- /wp:paragraph -->

<!-- wp:heading {"level":4} -->
<h4>Custom WAF</h4>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>In order to mimic the TestServer there is a class called <a href="https://docs.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.mvc.testing.webapplicationfactory-1?view=aspnetcore-5.0" target="_blank" rel="noreferrer noopener">WebApplicationFactory</a> (WAF) which bootstraps the application in memory.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>In your <strong><em>TDD.Tests</em></strong> project create a file named <em>PatientTestsDbWAF.cs</em> with the following code.</p>
<!-- /wp:paragraph -->

```
using System.Linq;
using Microsoft.EntityFrameworkCore;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc.Testing;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.AspNetCore;


namespace TDD.Tests
{
    public class PatientTestsDbWAF<TStartup> : WebApplicationFactory<TStartup> where TStartup : class
    {

        protected override IWebHostBuilder CreateWebHostBuilder()
        {
            return WebHost.CreateDefaultBuilder()
                .UseStartup<TStartup>();
        }
        protected override void ConfigureWebHost(IWebHostBuilder builder)
        {
            builder.ConfigureServices(async services =>
           {
               // Remove the app's DbContext registration.
               var descriptor = services.SingleOrDefault(
                      d => d.ServiceType ==
                          typeof(DbContextOptions<DataContext>));

               if (descriptor != null)
               {
                   services.Remove(descriptor);
               }

               // Add DbContext using an in-memory database for testing.
               services.AddDbContext<DataContext>(options =>
                  {
                      // Use in memory db to not interfere with the original db.
                      options.UseInMemoryDatabase("PatientTestsTDD.db");
                  });
           });
        }
    }
}
```

<!-- wp:paragraph -->
<p>We are removing the applications DbContext and adding an <strong>in memory</strong> DbContext. It is a necessary step since we don't want to interfere with the original database. </p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Secondly, we are initialising the database with some dummy data. </p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Since, DataContext is a custom class, it will give compiler error. So, we need to create it.</p>
<!-- /wp:paragraph -->

<!-- wp:heading {"level":4} -->
<h4>Data Context</h4>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Therefore, in your <strong>TDD project</strong>, create a file named <em>DataContext.cs</em> with the following code.</p>
<!-- /wp:paragraph -->

```
using Microsoft.EntityFrameworkCore;

namespace TDD
{
    public class DataContext : DbContext
    {
        public DataContext(DbContextOptions options) : base(options) { }

        // For storing the list of patients and their state
        public DbSet<Patient> Patient { get; set; }

        // For the storying the rooms along with their types and capacity
        public DbSet<Room> Room { get; set; }

        // For logging which patients are currently admitted to which room
        public DbSet<RoomPatient> RoomPatient { get; set; }

    }
}
```

<!-- wp:paragraph -->
<p>Here Patient, Room &amp; RoomPatient are Entity classes with the required properties, which we will create next.</p>
<!-- /wp:paragraph -->

<!-- wp:heading {"level":4} -->
<h4>Patient</h4>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Again, in your <strong>TDD project</strong>, create a file named <em>Patient.cs</em> and paste in the code below.</p>
<!-- /wp:paragraph -->

```
using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;

namespace TDD
{
    public class Patient
    {
        [Key]
        [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
        public int Id { get; set; }
      
        public String Name { get; set; }

        public String PhoneNumber { get; set; }

        public int Age { get; set; }

        public String Gender { get; set; }
    }
}
```

<!-- wp:heading {"level":4} -->
<h4>Room</h4>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Create another file named <em>Room.cs</em> with the following code.</p>
<!-- /wp:paragraph -->

```
using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;

namespace TDD
{
    public class Room
    {
      	[Key]
        [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
        public int Id { get; set; }
      
        public String RoomType { get; set; }

        public int CurrentCapacity { get; set; }

        public int MaxCapacity { get; set; }
    }
}
```

<!-- wp:heading {"level":4} -->
<h4>RoomPatient</h4>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Create the last model file <em>RoomPatient.cs</em> with the following code.</p>
<!-- /wp:paragraph -->

```
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;

namespace TDD
{
    public class RoomPatient
    {
        [Key]
        [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
        public int Id { get; set; }

        [Required]
        public int RoomId { get; set; }

        [ForeignKey("RoomId")]
        public Room Room { get; set; }

        [Required]
        public int PatientId { get; set; }

        [ForeignKey("PatientId")]
        public Patient Patient { get; set; }
    }
}
```

<!-- wp:paragraph -->
<p>Now you shouldn't be getting any compiler error.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Lastly, remove the WeatherForecast.cs and WeatherForecastController.cs files. </p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Go to your terminal in VS Code and run the below command.</p>
<!-- /wp:paragraph -->

```
cd TDD.Tests
dotnet test
```

<!-- wp:paragraph -->
<p>You will see a nice green result which says 1 test passed.</p>
<!-- /wp:paragraph -->

<!-- wp:image {"id":440,"sizeSlug":"large","linkDestination":"none"} -->
<figure class="wp-block-image size-large"><img src="https://arjavdave.com/wp-content/uploads/2021/04/Test_Success_1-1024x211.png" alt="" class="wp-image-440"/><figcaption>Test Success</figcaption></figure>
<!-- /wp:image -->

<!-- wp:heading {"level":4} -->
<h4>Patient Controller</h4>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Unfortunately dotnet doesn't provide a way to directly test the model's in itself. So, we will have to create a controller to test it. </p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Go ahead and create <em>PatientController.cs</em> in the Controllers folder in <strong>TDD project</strong> with the below code.</p>
<!-- /wp:paragraph -->

```
using Microsoft.AspNetCore.Mvc;

namespace TDD.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    public class PatientController : Controller
    {
        [HttpPost]
        public IActionResult AddPatient([FromBody] Patient Patient)
        {
            // TODO: Insert the patient into db
            return Created("/patient/1", Patient);
        }
    }
}
```

<!-- wp:paragraph -->
<p>We created an api to add a patient. In order to test our model we will call this api.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>That is all the things required to start testing.</p>
<!-- /wp:paragraph -->

<!-- wp:heading -->
<h2>Model Validation Tests</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Since, we have setup the basic code for testing, let's write a test that fails. We will start our testing with the model validation tests.</p>
<!-- /wp:paragraph -->

<!-- wp:heading {"level":4} -->
<h4>Failing (Red) State</h4>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Let's create a new file named <em>PatientTests.cs</em> in your <strong>TDD.Tests project</strong> and delete the file named <em>UnitTest1.cs</em>. Copy the below code in your file.</p>
<!-- /wp:paragraph -->

```
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
using Xunit;
using System.Text;
using System.Text.Json;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.AspNetCore.Mvc.Testing;
using System;
using System.Collections.Generic;
using Microsoft.EntityFrameworkCore;

namespace TDD.Tests
{
    public class PatientTests : IClassFixture<PatientTestsDbWAF<Startup>>
    {
        // HttpClient to call our api's
        private readonly HttpClient httpClient;
        public WebApplicationFactory<Startup> _factory;

        public PatientTests(PatientTestsDbWAF<Startup> factory)
        {
            _factory = factory;

            // Initiate the HttpClient
            httpClient = _factory.CreateClient();
        }

        [Theory]
        [InlineData("Test Name 2", "1234567891", 20, "Male", HttpStatusCode.Created)]
        [InlineData("T", "1234567891", 20, "Male", HttpStatusCode.BadRequest)]
        [InlineData("A very very very very very very loooooooooong name", "1234567891", 20, "Male", HttpStatusCode.BadRequest)]
        [InlineData(null, "1234567890", 20, "Invalid Gender", HttpStatusCode.BadRequest)]
        [InlineData("Test Name", "InvalidNumber", 20, "Male", HttpStatusCode.BadRequest)]
        [InlineData("Test Name", "1234567890", -10, "Male", HttpStatusCode.BadRequest)]
        [InlineData("Test Name", "1234567890", 20, "Invalid Gender", HttpStatusCode.BadRequest)]
        [InlineData("Test Name", "12345678901234444", 20, "Invalid Gender", HttpStatusCode.BadRequest)]
        public async Task PatientTestsAsync(String Name, String PhoneNumber, int Age, String Gender, HttpStatusCode ResponseCode)
        {
            var scopeFactory = _factory.Services;
            using (var scope = scopeFactory.CreateScope())
            {
                var context = scope.ServiceProvider.GetService<DataContext>();
                
                // Initialize the database, so that 
                // changes made by other tests are reset. 
                await DBUtilities.InitializeDbForTestsAsync(context);
                
                // Arrange
                var request = new HttpRequestMessage(HttpMethod.Post, "api/patient");

                request.Content = new StringContent(JsonSerializer.Serialize(new Patient
                {
                    Name = Name,
                    PhoneNumber = PhoneNumber,
                    Age = Age,
                    Gender = Gender
                }), Encoding.UTF8, "application/json");

                // Act
                var response = await httpClient.SendAsync(request);

                // Assert
                var StatusCode = response.StatusCode;
                Assert.Equal(ResponseCode, StatusCode);
            }
        }
    }
}
```

<!-- wp:paragraph -->
<p>[Theory] attribute allows us to mention different parameters for our tests. Consequently, we don't have to write different tests for all the combinations.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Also, DBUtilities is a utility class to reinitialise the database to it's initial state. This might seem trivial when we have 1 or 2 tests but, gets critical as we add more tests. </p>
<!-- /wp:paragraph -->

<!-- wp:heading {"level":4} -->
<h4>DBUtilities</h4>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>The DBUtilities class will initialise your database with 1 patient and 3 different type of rooms. </p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Create a file named <em>DBUtilities.cs</em> in your <strong><em>TDD.Tests</em></strong> project with the below code.</p>
<!-- /wp:paragraph -->

```
using System.Threading.Tasks;

namespace TDD.Tests
{
    // Helps to initialise the database either from the WAF for the first time
    // Or before running each test.
    public class DBUtilities
    {

        // Clears the database and then,
        //Adds 1 Patient and 3 different types of rooms to the database
        public static async Task InitializeDbForTestsAsync(DataContext context)
        {
            context.RoomPatient.RemoveRange(context.RoomPatient);
            context.Patient.RemoveRange(context.Patient);
            context.Room.RemoveRange(context.Room);
            
            // Arrange
            var Patient = new Patient
            {
                Name = "Test Patient",
                PhoneNumber = "1234567890",
                Age = 20,
                Gender = "Male"
            };
            context.Patient.Add(Patient);

            var ICURoom = new Room
            {
                RoomType = "ICU",
                MaxCapacity = 1,
                CurrentCapacity = 1
            };
            context.Room.Add(ICURoom);

            var GeneralRoom = new Room
            {
                RoomType = "General",
                MaxCapacity = 2,
                CurrentCapacity = 2
            };
            context.Room.Add(GeneralRoom);

            var PremiumRoom = new Room
            {
                RoomType = "Premium",
                MaxCapacity = 1,
                CurrentCapacity = 1
            };
            context.Room.Add(PremiumRoom);

            await context.SaveChangesAsync();
        }
    }
}
```

<!-- wp:paragraph -->
<p>Go ahead and run the <em>dotnet test</em> command again and you will see 1 passed and 4 failed tests. This is because the 4 tests were expecting BadRequest but getting a Created result. </p>
<!-- /wp:paragraph -->

<!-- wp:image {"id":442,"sizeSlug":"large","linkDestination":"none"} -->
<figure class="wp-block-image size-large"><img src="https://arjavdave.com/wp-content/uploads/2021/04/failed_tests-1024x195.png" alt="" class="wp-image-442"/><figcaption>Failing (Red) State</figcaption></figure>
<!-- /wp:image -->

<!-- wp:paragraph -->
<p>Let's fix it!</p>
<!-- /wp:paragraph -->

<!-- wp:heading {"level":4} -->
<h4>Success (Green) State</h4>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>In order to fix these we need to add attributes to our <em>Patient.cs</em> class.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Update the <em>Patient.cs</em> file as below.</p>
<!-- /wp:paragraph -->

```
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;

namespace TDD
{
    public class Patient : IValidatableObject
    {
        [Key]
        [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
        public int Id { get; set; }

        [Required]
        [StringLength(40, MinimumLength = 2, ErrorMessage = "The name should be between 2 & 40 characters.")]
        public String Name { get; set; }

        [Required]
        [DataType(DataType.PhoneNumber)]
        [RegularExpression(@"^(\d{7,12})$", ErrorMessage = "Not a valid phone number")]
        public String PhoneNumber { get; set; }

        [Required]
        [Range(1, 150)]
        public int Age { get; set; }

        [Required]
        public String Gender { get; set; }

        public Boolean IsAdmitted { get; set; }

        public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
        {
            // Only Male, Female or Other gender are allowed
            if (Gender.Equals("Male", System.StringComparison.CurrentCultureIgnoreCase) == false &&
                Gender.Equals("Female", System.StringComparison.CurrentCultureIgnoreCase) == false &&
                Gender.Equals("Other", System.StringComparison.CurrentCultureIgnoreCase) == false)
            {
                yield return new ValidationResult("The gender can either be Male, Female or Other");
            }

            yield return ValidationResult.Success;
        }
    }
}
```

<!-- wp:paragraph -->
<p>Here, we have added the required attributes. We have also implemented the <em>IValidatableObject</em> interface so that we can verify the <em>Gender</em>.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Time to run the <em>dotnet test</em> command. You will see a nice green line saying 5 tests passed.</p>
<!-- /wp:paragraph -->

<!-- wp:image {"id":443,"sizeSlug":"large","linkDestination":"none"} -->
<figure class="wp-block-image size-large"><img src="https://arjavdave.com/wp-content/uploads/2021/04/Tests_passed_2-1024x244.png" alt="" class="wp-image-443"/></figure>
<!-- /wp:image -->

<!-- wp:paragraph -->
<p>You can add more edge case scenarios in the <em>InlineData</em> to test the Patient model validation tests thoroughly.</p>
<!-- /wp:paragraph -->

<!-- wp:heading -->
<h2>Duplicate Patient Test</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>We shall now create a test which fails when we try to add a duplicate patient.</p>
<!-- /wp:paragraph -->

<!-- wp:heading {"level":4} -->
<h4>Failing (Red) Test</h4>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Create another test in your class <em>PatientTests. </em>Add the below code.</p>
<!-- /wp:paragraph -->

```
[Fact]
public async Task PatientDuplicationTestsAsync()
{
    var scopeFactory = _factory.Services;
    using (var scope = scopeFactory.CreateScope())
    {
        var context = scope.ServiceProvider.GetService<DataContext>();
        await DBUtilities.InitializeDbForTestsAsync(context);

        // Arrange
        var Patient = await context.Patient.FirstOrDefaultAsync();

        var Request = new HttpRequestMessage(HttpMethod.Post, "api/patient");
        Request.Content = new StringContent(JsonSerializer.Serialize(Patient), Encoding.UTF8, "application/json");

        // Act
        var Response = await httpClient.SendAsync(Request);

        // Assert
        var StatusCode = Response.StatusCode;
        Assert.Equal(HttpStatusCode.BadRequest, StatusCode);
    }
}
```

<!-- wp:paragraph -->
<p>We have used a [Fact] attribute instead of [Theory] attribute here since we don't want to test the same method with different parameters. Instead, we want to make the same request twice.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Run <em><strong>dotnet test </strong></em>to run our newly created test. The test will fail with message <em>Assert.Equal() Failure</em>. Time to fix it.</p>
<!-- /wp:paragraph -->

<!-- wp:heading {"level":4} -->
<h4>Success (Green) Test</h4>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>To fix the failing test we need to add the implementation for the AddPatient method in <em>PatientController.cs</em>. Update the file's code as below.</p>
<!-- /wp:paragraph -->

```
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;

namespace TDD.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    public class PatientController : Controller
    {
        private readonly DataContext _context;

        public PatientController(DataContext context)
        {
            _context = context;
        }
        [HttpPost]
        public async Task<IActionResult> AddPatientAsync([FromBody] Patient Patient)
        {
            var FetchedPatient = await _context.Patient.FirstOrDefaultAsync(x => x.PhoneNumber == Patient.PhoneNumber);
            // If the patient doesn't exist create a new one
            if (FetchedPatient == null)
            {
                _context.Patient.Add(Patient);
                await _context.SaveChangesAsync();
                return Created($"/patient/{Patient.Id}", Patient);
            }
            // Else throw a bad request
            else
            {
                return BadRequest();
            }
        }
    }
}
```
<!-- wp:paragraph -->
<p>Run the <strong><em>dotnet test </em></strong>again and you will see that the test has passed.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>You can run all the tests by calling <strong><em>dotnet test.</em></strong></p>
<!-- /wp:paragraph -->

<!-- wp:heading -->
<h2>Important Notes</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>As you add more models/domains like Doctors, Staff, Instruments etc. You will have to create more tests. Make sure to have a different WAF, utility wrappers and different Test files for each of them.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Secondly, the tests in the same file do not run in parallel. But, the tests from different files do run in parallel. Therefore, each WAF should have a different database name so that data is not misconfigured. </p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Lastly, the connections to the original database still needs to be setup in the main project. </p>
<!-- /wp:paragraph -->

<!-- wp:heading -->
<h2>Thought Process</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>The thought process for creating tests for all scenarios are similar. </p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>That is, you should first identify the requirements. Then, set up a skeleton of methods and classes without implementation. Write tests to verify the implementation. Finally, refactor as needed and rerun the tests.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>This tutorial didn't include authentication and authorisation for api's. You can <a href="https://arjavdave.com/2021/03/31/net-5-setup-authentication-and-authorisation/" target="_blank" rel="noreferrer noopener">read here</a> on how to set it up.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Since, it is not possible to cover all the test cases, I have created a <a href="https://github.com/shenanigan/tdd-demo" target="_blank" rel="noreferrer noopener">repository on Github</a>. It covers the implementation for all the test cases and the implementation as well. </p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>You can find the <a href="https://github.com/shenanigan/tdd-demo" target="_blank" rel="noreferrer noopener">project here</a>.</p>
<!-- /wp:paragraph -->

<!-- wp:heading -->
<h2>Conclusion</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>In order for TDD to be effective you really need to have a clear idea of what the requirements are. If the requirements keep on changing it would get very tough to maintain the tests as well as the project. </p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>TDD mainly covers unit, integration &amp; functional tests. You will still have to do UAT, Configuration &amp; Production testing before you go live. </p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Having said that, TDD is really helpful in making your project bug free. Secondly, it boosts your confidence for the implementation. You will be able to change bits &amp; pieces of your code as long as the tests pass. Lastly, it provides a better architecture for your project. </p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Hope you like the article. Let me know your thoughts or feedback. </p>
<!-- /wp:paragraph -->

[Check more tutorials on .NET here.](https://arjavdave.com)