2017-06-14 75 views
1

錯誤:InMemory的DbContext拋出錯誤時,集成測試

Message: System.InvalidOperationException : The instance of entity type 'Program' cannot be tracked because another instance of this type with the same key is already being tracked. When adding new entities, for most key types a unique temporary key value will be created if no key is set (i.e. if the key property is assigned the default value for its type). If you are explicitly setting key values for new entities, ensure they do not collide with existing entities or temporary values generated for other new entities. When attaching existing entities, ensure that only one entity instance with a given key value is attached to the context.

集成測試:

public class ProgramControllerIntegrationTests : MappingTestsHelper 
    { 
     private readonly IMapper _mapper; 
     private readonly Repository<ApplicationDbContext> _repository; 
     private ProgramService _programService; 
     private readonly ProgramController _classUnderTest; 
     private readonly ValidatorService _validatorService; 
     private readonly FluentValidatorFactory _fluentValidatorFactory; 
     private readonly ClaimsService _claimsService; 

     public ProgramControllerIntegrationTests() 
     { 
      var container = new Container(); 
      container.Configure(c => { 
       c.AddRegistry<DependencyInjectionRegistry>(); 
       c.For<AbstractValidator<CreateViewModel>>().Use<CreateViewModelValidator>(); 
      }); 

      _mapper = Mapper.Instance; 
      _repository = new Repository<ApplicationDbContext>(GetContextWithData()); 
      _programService = new ProgramService(_repository, _mapper); 
      _fluentValidatorFactory = new FluentValidatorFactory(container); 
      _validatorService = new ValidatorService(_fluentValidatorFactory); 
      _claimsService = new ClaimsService(); 
      _classUnderTest = new ProgramController(_programService, _claimsService, _mapper, _validatorService); 
     } 

     public class GetAll : ProgramControllerIntegrationTests 
     { 
      [Fact] 
      public async void DoRequestForAllPrograms_ReturnSuccessHttpStatusAndListViewModelList() 
      { 
       var result = await _classUnderTest.GetAll() as ObjectResult; ; 

       result.ShouldBeOfType<OkObjectResult>(); 
       result.StatusCode.ShouldBe(200); 
       result.Value.ShouldBeOfType<List<ListViewModel>>(); 
      } 
     } 

     public class Create : ProgramControllerIntegrationTests 
     { 
      [Fact] 
      public async void DoRequestForCreateWithCorrectData_ReturnCreatedHttpStatus() 
      { 
       var createviewmodel = new CreateViewModel 
       { 
        Name = "Muskel Deutsche Program", 
        Length = 1, 
        TimesPerWeek = 3, 
        Type = (byte)ProgramTypeEnum.MuscleGain 
       }; 

       var result = await _classUnderTest.Create(createviewmodel) as ObjectResult; 

       result.ShouldBeOfType<OkObjectResult>(); 
       result.StatusCode.ShouldBe(201); 
      } 

      [Fact] 
      public async void DoRequestForCreateWithMissingData_ReturnBadRequestHttpStatus() 
      { 
       var createviewmodel = new CreateViewModel 
       { 
        Type = (byte)ProgramTypeEnum.MuscleGain 
       }; 

       var result = await _classUnderTest.Create(createviewmodel) as ObjectResult; 

       result.ShouldBeOfType<BadRequestObjectResult>(); 
       result.StatusCode.ShouldBe(400); 
      } 
     } 

     private ApplicationDbContext GetContextWithData() 
     { 
      var options = new DbContextOptionsBuilder<ApplicationDbContext>() 
       .UseInMemoryDatabase(Guid.NewGuid().ToString()) 
       .Options; 

      var context = new ApplicationDbContext(options); 

      var programs = new List<Context.Models.Program> 
      { 
       new Context.Models.Program 
       { 
        CreatedBy = "d0806514-cbce-47b7-974f-c50f77d5e89c", 
        CreatedDate = new DateTime(2010, 10, 10), 
        Id = 1, 
        IsActive = true, 
        IsDeleted = false, 
        Length = 1, 
        ModifiedBy = "d0806514-cbce-47b7-974f-c50f77d5e89c", 
        ModifiedDate = new DateTime(2010, 10, 10), 
        Name = "Big Muscle", 
        TimesPerWeek = 1 

       }, 
       //new Context.Models.Program 
       //{ 
       // CreatedBy = "d0806514-cbce-47b7-974f-c50f77d5e89c", 
       // CreatedDate = new DateTime(2010, 10, 10), 
       // Id = 1, 
       // IsActive = true, 
       // IsDeleted = false, 
       // Length = 1, 
       // ModifiedBy = "d0806514-cbce-47b7-974f-c50f77d5e89c", 
       // ModifiedDate = new DateTime(2010, 10, 10), 
       // Name = "Stay Fit", 
       // TimesPerWeek = 1 

       //} 
      }; 

      context.AddRangeAsync(programs); 

      context.SaveChanges(); 

      return context; 
     } 
    } 

問題出現在DoRequestForCreateWithCorrectData_ReturnCreatedHttpStatus方法,其中我使用上下文來添加新項目到內存數據庫。同樣的問題出現時,我想同時添加更多的項目上下文,所以我認爲我做了初始化錯誤的方式。

+1

不知道如果是這樣的問題,但'SaveChanges'在'AddRangeAsync'沒有「await」或「Wait」的情況下完成後聽起來不太好。爲什麼不簡單地'AddRange'。 –

回答

0

問題是,來自預製數據的Id是1和1,所以這是第一個錯誤,爲什麼兩個都沒有一起工作。另一個問題是它創建ID爲1,這是已經使用預製的數據創造了新的記錄時,所以我只是改變了標識在預製到98和99

private ApplicationDbContext GetContextWithData() 
    { 
     var options = new DbContextOptionsBuilder<ApplicationDbContext>() 
      .UseInMemoryDatabase(Guid.NewGuid().ToString()) 
      .Options; 

     var context = new ApplicationDbContext(options); 

     var programs = new List<Context.Models.Program> 
     { 
      new Context.Models.Program 
      { 
       CreatedBy = "d0806514-cbce-47b7-974f-c50f77d5e89c", 
       CreatedDate = new DateTime(2010, 10, 10), 
       Id = 98, 
       IsActive = true, 
       IsDeleted = false, 
       Length = 1, 
       ModifiedBy = "d0806514-cbce-47b7-974f-c50f77d5e89c", 
       ModifiedDate = new DateTime(2010, 10, 10), 
       Name = "Big Muscle", 
       TimesPerWeek = 1 

      }, 
      new Context.Models.Program 
      { 
       CreatedBy = "d0806514-cbce-47b7-974f-c50f77d5e89c", 
       CreatedDate = new DateTime(2010, 10, 10), 
       Id = 99, 
       IsActive = true, 
       IsDeleted = false, 
       Length = 1, 
       ModifiedBy = "d0806514-cbce-47b7-974f-c50f77d5e89c", 
       ModifiedDate = new DateTime(2010, 10, 10), 
       Name = "Stay Fit", 
       TimesPerWeek = 1 

      } 
     }; 

     context.AddRange(programs); 

     context.SaveChanges(); 

     return context; 
    }