MZG
MZG

Reputation: 335

Auto increment primary key in mocked db context

Does anyone know how can I have auto increment primary keys in my mocked db context? I am unit testing a method and when I want to add two items to my mocked db context and I get an error saying "An item with the same key has already been added". so I should find a way to setup my db context mock such that when every time an item is added, it will be added with different primary key. this is my method in service class:

public async Task<ProductDTO> CreateProduct(ProductDTO dto)
{
 foreach (var i in dto.Products)
            {
                if (i.ProductId == 0)
                {
                    // New product
                    var product = Product.CreateMyProductDto(i);
                    _db.Products.Add(product);
                }
            }

 // rest of the code …

}

so here we look at dto.products and if any product has productId equal to zero then we create our product by calling Product.CreateMyProductDto function and add it to Products table. In my unit test below I have two products with productId = 0 hence they should be added to the Products table but I get an error for adding the second product because of the primary key.

[Fact]
public async Task TestForCreateProduct()
{
    //Arrange
     List<Product> products = new List<Product>();

     Product product1 = new Poduct()
     {
           ProductId = 0
     };

     Product product2 = new Poduct()
     {
          ProductId = 0
     };

     // add to the products list
      products.Add(product1);
      products.Add(product2);
      
      ProductDTo dto = new ProductDTO()
      {     
          Products = products
      };

     // create mock
     DbContextMock<MyContext> context_Moq = new DbContextMock<MyContext>(DummyOptions);
        
     // set up mock
     context_Moq.CreateDbSetMock(x => x.Products, new[]
     {
          new Product { EntityId = 1, Name = "product1"},
          new Product { EntityId = 2, Name = "product2"},
          new Product { EntityId = 3, Name = "product3"}
     });

     var service = new myService(context_Moq.Object);

     // Act
     var result = await service.CreateProduct(dto);
          
     // Assert
     Assert.Equal(5, context_Moq.Object.Products.Count());
}

I am using .NET core3 so can anyone help me to fix this error? I need to have auto increment primary keys in my mocked db context.

Upvotes: 1

Views: 1361

Answers (1)

MZG
MZG

Reputation: 335

I finally could solve this. As you see in the following, EntityId is primary key in my Product class and I used [Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)] attribute in order to have Auto-increment identity column for EntityId

public class Product
{
    [Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public long EntityId { get; set; }
       
      // rest of the code
}

In this case items are added to my mocked dbContext with EntityIds starting from 1. Suppose you set up your dbContext with one item that has EntityId 1. Then you call the Add function to add a product to Products table you will get the same error since it tries to add a product with EntityId 1 which was already in your mocked dbContext. So Items with the same keys cannot be in the db. You may NOT use this attribute for your primary key in 2 cases:

  1. If your primary key is foreign key
  2. when you have ValueGeneratedNever() method on your primary key

Upvotes: 2

Related Questions