loading...
Cover image for From TDD to DDD: Building a .NET Core Web API - Part 3

From TDD to DDD: Building a .NET Core Web API - Part 3

lucianopereira86 profile image LUCIANO DE SOUSA PEREIRA ・3 min read

The complete project can be found here: https://github.com/lucianopereira86/CRUD-NetCore-TDD

Technologies

Post User • Fact

Green Step

Create a folder named "Models" inside the Infra project with a file named "User.cs".

Add the following code into it:

namespace CRUD_NETCore_TDD.Infra.Models
{
    public class User
    {
        public User()
        {

        }
        public User(int Id, string Name, int Age, bool IsActive)
        {
            this.Id = Id;
            this.Name = Name;
            this.Age = Age;
            this.IsActive = IsActive;
        }
        public int Id { get; set; }
        public string Name { get; set; }
        public int Age { get; set; }
        public bool IsActive { get; set; }
    }
}

The "User" model is completed. Inside the "PostUserTest.cs" file, copy and paste the "Fact_PostUser_NoModelNoRepository" method and comment the original. Change the copy's name to
"Fact_PostUser_NoRepository" and import the "User" class. The full code will be like this:

using CRUD_NETCore_TDD.Infra.Models;
using Xunit;

namespace CRUD_NETCore_TDD.Test.Tests
{
    public class PostUserTest
    {
        #region THEORY
        #endregion
        #region FACT
        //[Fact]
        //public void Fact_PostUser_NoClassNoRepository ()
        //{
        //    // EXAMPLE
        //    var user = new User("LUCIANO PEREIRA", 33, true);

        //    // REPOSITORY
        //    ctx.User.Add(user);
        //    ctx.SaveChanges();

        //    // ASSERT
        //    Assert.Equal(1, user.Id);
        //}

        [Fact]
        public void Fact_PostUser_NoRepository()
        {
            // EXAMPLE
            var user = new User(0, "LUCIANO PEREIRA", 33, true);

            // REPOSITORY
            ctx.User.Add(user);
            ctx.SaveChanges();

            // ASSERT
            Assert.Equal(1, user.Id);
        }
        #endregion
    }
}

Now, it is only missing the "ctx" object to make the code compile.
It will be necessary to install 3 packages through Nuget:

  • "Microsoft.EntityFrameworkCore" and "Microsoft.EntityFrameworkCore.SqlServer" packages inside the Infra project;
  • "Microsoft.EntityFrameworkCore.InMemory" package inside the Test project.

Create a new folder named "Repositories" inside the Infra project containing the "MyContext.cs" file with the following code:

using CRUD_NETCore_TDD.Infra.Models;
using Microsoft.EntityFrameworkCore;

namespace CRUD_NETCore_TDD.Infra.Repositories
{
    public class MyContext: DbContext
    {
        public DbSet<User> User { get; set; }
        public MyContext(DbContextOptions<MyContext> options) : base(options)
        {

        }

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            base.OnModelCreating(modelBuilder);
            modelBuilder.Entity<User>(e =>
            {
                e
                .ToTable("user")
                .HasKey(k => k.Id);

                e
                .Property(p => p.Id)
                .ValueGeneratedOnAdd();
            });
        }
    }
}

What we have here is the basics for the EF Core to work in our project. The "user" table does not need to exist yet because will make the database to run in runtime memory.
Inside the Test project, create another file inside the "Tests" folder named "BaseTest.cs". It will be a super class containing the following code:

using CRUD_NETCore_TDD.Infra.Repositories;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;

namespace CRUD_NETCore_TDD.Test.Tests
{
    public class BaseTest
    {
        protected MyContext ctx;
        public BaseTest(MyContext ctx = null)
        {
            this.ctx = ctx ?? GetInMemoryDBContext();
        }
        protected MyContext GetInMemoryDBContext()
        {
            var serviceProvider = new ServiceCollection()
                .AddEntityFrameworkInMemoryDatabase()
                .BuildServiceProvider();

            var builder = new DbContextOptionsBuilder<MyContext>();
            var options = builder.UseInMemoryDatabase("test").UseInternalServiceProvider(serviceProvider).Options;

            MyContext dbContext = new MyContext(options);
            dbContext.Database.EnsureDeleted();
            dbContext.Database.EnsureCreated();
            return dbContext;
        }
    }
}

The "BaseTest" class is responsive for instantiating the "MyContext" class and make it run in memory without the need of a database previously created. All the write and read operations will work perfectly. If another "MyContext" instance exists, it will be passed as parameter to the constructor.

Make the "PostUserTest" class to implement the "BaseTest" class and the code will be finally be able to compile. Copy and paste the "Fact_PostUser_NoRepository" method, comment the original and rename the copy to "Fact_PostUser". The code will be like this:

using CRUD_NETCore_TDD.Infra.Models;
using Xunit;

namespace CRUD_NETCore_TDD.Test.Tests
{
    public class PostUserTest: BaseTest
    {
        #region THEORY
        #endregion
        #region FACT
        //[Fact]
        //public void Fact_PostUser_NoClassNoRepository ()
        //{
        //    // EXAMPLE
        //    var user = new User("LUCIANO PEREIRA", 33, true);

        //    // REPOSITORY
        //    ctx.User.Add(user);
        //    ctx.SaveChanges();

        //    // ASSERT
        //    Assert.Equal(1, user.Id);
        //}

        //[Fact]
        //public void Fact_PostUser_NoRepository()
        //{
        //    // EXAMPLE
        //    var user = new User(0, "LUCIANO PEREIRA", 33, true);

        //    // REPOSITORY
        //    ctx.User.Add(user);
        //    ctx.SaveChanges();

        //    // ASSERT
        //    Assert.Equal(1, user.Id);
        //}

        [Fact]
        public void Fact_PostUser()
        {
            // EXAMPLE
            var user = new User(0, "LUCIANO PEREIRA", 33, true);

            // REPOSITORY
            ctx.User.Add(user);
            ctx.SaveChanges();

            // ASSERT
            Assert.Equal(1, user.Id);
        }
        #endregion
    }
}

Run the tests with the Test Manager to see the result:

print06

Finally, our Green step is done!

Next

Time to refact the code.

Posted on by:

lucianopereira86 profile

LUCIANO DE SOUSA PEREIRA

@lucianopereira86

Luciano de Sousa Pereira. Brazilian. Bacharel degree in Computer Engineering. Full Stack Developer with 5 years of experience in multiple frameworks and programming languages.

Discussion

markdown guide