Тестирование метода обновления в сервисе - «Экземпляр типа объекта не может быть отслежен» - [XUnit] [EntityFrameworkCore] - PullRequest
0 голосов
/ 16 октября 2019

Я хочу проверить метод обновления в моей службе, и я не могу, потому что он возвращает мне эту ошибку во время выполнения.

Сообщение: System.InvalidOperationException: экземпляр типа сущности 'Objective' не может бытьотслеживается, поскольку другой экземпляр с тем же значением ключа для {'Id'} уже отслеживается. При подключении существующих объектов убедитесь, что подключен только один экземпляр объекта с данным значением ключа. Рассмотрите возможность использования 'DbContextOptionsBuilder.EnableSensitiveDataLogging', чтобы увидеть конфликтующие ключевые значения.

Это Мой тестовый класс.

public class ObjectiveShould: IClassFixture<TestServiceCollectionFactory>
    {
        TestServiceCollectionFactory _services;
        private readonly IObjectiveService objectiveService;

        public ObjectiveShould()
        {
            _services = TestServiceCollectionFactory.Create();
            objectiveService = _services.ObjectiveService;
        }

        [Fact]
        [Trait("Category", "Integration test")]
        public async Task Update_Should()
        {
            InitializeData();
            var user = await InitializeUserAndRole("CCC", "member");

            var model = new ObjectiveCreateDTO()
            {
                GoalDueDate = new DateTime(2019, 12, 8),
                Goal = 5,
            };

            var add = await objectiveService.Update(user, model, 1);

            var objs = await _services.OrganizationsContext.Objectives.FirstOrDefaultAsync(x => x.Id == add.Id);

            Assert.NotNull(objs);
        }

        private void InitializeData()
        {
            _services.OrganizationsContext.AddRange(EntityBuilder.GetObjectives());
            _services.OrganizationsContext.SaveChanges();
        }

        private async Task<ApplicationUser> InitializeUserAndRole(string userId, string roleName)
        {
            var user = _services.UserContext.Set<ApplicationUser>().FirstOrDefault(e => e.Id == userId);
            await _services.RoleManager.CreateAsync(new IdentityRole { Id = new Guid().ToString(), Name = roleName });
            await _services.UserManager.AddToRoleAsync(user, roleName);
            return user;
        }
    }

Метод обновления в tasksService

        public async Task<ObjectiveInfoDTO> Update(ApplicationUser invoker, ObjectiveCreateDTO model, int id)
        {
            _validate.ValidateUser(invoker, _localizer);

            if (!string.IsNullOrEmpty(model.AssigneeId) && model.TeamAssigneeId.HasValue)
            {
                throw new CustomException("WrongParameter", HttpStatusCode.BadRequest, _localizer["WrongParameter"]);
            }

            var objective = await _objectiveRepository.GetById(id);


            _mapper.Map(model, objective);

            await _objectiveRepository.Update(objective);

            return _mapper.Map<ObjectiveInfoDTO>(objective);

        }

Обновление в репозитории

        public async Task Update(T entity)
        {
            _dbContext.Entry(entity).State = EntityState.Modified;
            await _dbContext.SaveChangesAsync();
        }

Сбор службы тестирования

        public TestServiceCollectionFactory()
        {
            var services = new ServiceCollection();

            var mappingConfig = new MapperConfiguration(mc => {
                mc.AddProfile(new DomainToViewModelMappingProfile());
                mc.AddProfile(new ViewModelToDomainMappingProfile());
            });

            mapper = mappingConfig.CreateMapper();
            services.AddSingleton(mapper);

            services
                .AddSingleton<IConfiguration>(new ConfigurationBuilder().Build())
                .AddDbContext<UsersContext>(o => o.UseInMemoryDatabase("doerio"))
                .AddIdentity<ApplicationUser, IdentityRole>(options =>
                {
                    options.SignIn.RequireConfirmedEmail = true;
                    options.Password.RequireDigit = true;
                    options.Password.RequireLowercase = true;
                    options.Password.RequireNonAlphanumeric = false;
                    options.Password.RequireUppercase = true;
                    options.Password.RequiredLength = 8;
                })
                .AddEntityFrameworkStores<UsersContext>()
                .AddDefaultTokenProviders();

            services
                .AddDbContext<OrganizationsContext>(o => o.UseInMemoryDatabase("doerio"));

            services
                .AddDbContext<TasksContext>(o => o.UseInMemoryDatabase("doerio"));

            services
                .AddDbContext<AttributesContext>(o => o.UseInMemoryDatabase("doerio"));

            services.AddTransient(typeof(IOrganizationsRepository<>), typeof(OrganizationsRepository<>));

.....

            services.AddTransient<IObjectiveService, ObjectiveService>();

            var provider = services.BuildServiceProvider();

            UserContext = provider.GetRequiredService<UsersContext>();
            OrganizationsContext = provider.GetRequiredService<OrganizationsContext>();



            UserManager = provider.GetRequiredService<UserManager<ApplicationUser>>();
            RoleManager = provider.GetRequiredService<RoleManager<IdentityRole>>();

            ObjectiveService = provider.GetRequiredService<IObjectiveService>();
.....


        }

        public static TestServiceCollectionFactory Create()
        {
            var services = new TestServiceCollectionFactory();

            return services;
        }

        public void Dispose()
        {
            UserContext.Database.EnsureDeleted();
            UserContext.Dispose();
        }
    }

И GetObjectives в EntityBuilder

 public static List<Objective> GetObjectives()
        {
            return new List<Objective>
            {
                new Objective
                {
                    Title = "Obj 1",
                    PillarId = 1,
                    AssigneeId = "BBB",
                    OrganizationId = 3,

                    ....

                    Goal= 5,
                    MotivationalMessage ="you can!",
                    ObjectiveStatus = SharedKernel.Enums.ObjectiveStatus.COMPLETED,
                    Report = SharedKernel.Enums.Report.PILLAR,
                    Comments = new List<Comment> { new Comment { Message = "test", CreatedDate= new DateTime(2019, 08, 8) , Edited=false, UserId="AAA"} }
                },
                new Objective
                {
                    Title = "Obj 2",
                    PillarId = 1,
                    AssigneeId = "2",

                    ....

                    ObjectiveStatus = SharedKernel.Enums.ObjectiveStatus.IN_PROGRESS,
                    Report = SharedKernel.Enums.Report.STATICS_ONTIMETASKS,
                    Comments = new List<Comment> { new Comment { Message = "test", CreatedDate= new DateTime(2019, 08, 8) , Edited=false, UserId="AAA"} }
                }
};
}

И пробовал с другими операциями, такими как удаление и удаление, и это работалоправильно, проблема возникает, когда я пытаюсь сделать Update.

[Update] В методе GetById внутри Update в сервисе есть такой вызов:

        public async Task<T> GetById(int id)
        {
            return await _dbContext.Set<T>()
                //.AsNoTracking()
                .FirstOrDefaultAsync(e => e.Id == id);
        }

Если я прокомментирую строкуAsNoTracking, то тестовый запуск, но мне нужна эта строка для выполнения моего запроса.

Любые предложения?

...