Home > Back-end >  adding records to inmemorydatabase just once
adding records to inmemorydatabase just once

Time:02-13

I am trying to write my very first xunit test with Database, instead of mocking the DbContext I used the inMemoryDatabase as I read in articles, so I did like following

public class GetCustomersTest { DbContextOptions _context;

    public GetCustomersTest()
    {
        if (_context==null)
            _context = CreateContextForCustomer();
    }        
    
    [Theory]
    [InlineData(1)]
    [InlineData(2)]
    public void GetCustomerById_ShouldReturnCorrectObject(int id)
    {
        using (var context = new DataBaseContext(_context))
        {
            var customerByIdService = new GetCustomerByIdService(context);
            
            var customer = customerByIdService.Execute(id);
            var customerActual = context.Customers.Where(x => x.Id == id).SingleOrDefault();
            var customerTmp = new Customer()
            {
                Id = id,
                FirstName = customer.Data.FirstName,
                LastName = customer.Data.LastName,
                Phone = customer.Data.Phone,
                ClientNote = customer.Data.ClientNote
            };
            Assert.Equal(customerTmp.FirstName, customerActual.FirstName);
            Assert.Equal(customerTmp.LastName, customerActual.LastName);
            Assert.Equal(customerTmp.Phone, customerActual.Phone);
            Assert.Equal(customerTmp.ClientNote, customerActual.ClientNote);

        }
    }

    private DbContextOptions<DataBaseContext> CreateContextForCustomer() {

        var options = new DbContextOptionsBuilder<DataBaseContext>()
            .UseInMemoryDatabase(databaseName: "SalonDatabase")
            .Options;

        using (var context = new DataBaseContext(options))
        {
            context.Customers.Add(new Customer
            {
                Id = 1,
                FirstName = "User1",
                LastName = "Surname1",
                Phone = "123",
                ClientNote = ""
            });
            context.Customers.Add(new Customer
            {
                Id = 2,
                FirstName = "User2",
                LastName = "Surname2",
                Phone = "4567",
                ClientNote = "The best"
            });
            
            context.SaveChanges();
        }
        return options;
    }
}

it works find on [InlineData(1)] but when it comes to [InlineData(2)], it seems that it starts to run the constructor again , so as it wants to add the customerdata to table, it says that the record with that Id key exists.what is the best way for doing that?

CodePudding user response:

When building your DB context options, add a GUID to the database name to make it unique:

var options = new DbContextOptionsBuilder<DataBaseContext>()
    .UseInMemoryDatabase(databaseName: "SalonDatabase"   Guid.NewGuid().ToString())
    .Options;

Or if you're using a new enough language version you can use string interpolation instead of concatenation:

var options = new DbContextOptionsBuilder<DataBaseContext>()
    .UseInMemoryDatabase(databaseName: $"SalonDatabase{Guid.NewGuid()}")
    .Options;

If you do this then every test uses a brand new database, unaffected by any previous tests.

As @MicheleMassari says, it's good practice to follow the Arrange Act Assert pattern, so that it's clear which lines are setting things up ready for the test and which are performing the action that you want to test the outcome of.

  1. Arrange inputs and targets. Arrange steps should set up the test case. Does the test require any objects or special settings? Does it need to prep a database? Does it need to log into a web app? Handle all of these operations at the start of the test.
  2. Act on the target behavior. Act steps should cover the main thing to be tested. This could be calling a function or method, calling a REST API, or interacting with a web page. Keep actions focused on the target behavior.
  3. Assert expected outcomes. Act steps should elicit some sort of response. Assert steps verify the goodness or badness of that response. Sometimes, assertions are as simple as checking numeric or string values. Other times, they may require checking multiple facets of a system. Assertions will ultimately determine if the test passes or fails.

The code samples in that page are written in Python rather than C#, but the pattern is valid for unit tests in any language. In the case of your test, structuring the test in this way makes it clear whether you're testing the behaviour of GetCustomerByIdService.Execute or of Entity Framework's Where method.

  • Related