Example #1
0
        public void ShouldCreateSoftDeleteLog2()
        {
            var options = new DbContextOptionsBuilder <TestTrackerContext>()
                          .UseSqlServer(TestConnectionString)
                          .Options;

            //create a softdeletable entity and soft delete it
            var deletable = new SoftDeletableModel();

            using (TestTrackerContext ttc = new TestTrackerContext(options))
            {
                ttc.SoftDeletableModels.Add(deletable); //add
                ttc.SaveChanges();                      //add

                deletable.AssertAuditForAddition(ttc, deletable.Id, null, x => x.Id);

                ttc.SoftDeletableModels.Remove(deletable); //soft delete
                ttc.SaveChanges();                         //soft delete

                //assert for soft deletion
                deletable.AssertAuditForSoftDeletion(ttc, deletable.Id, null, new AuditLogDetail
                {
                    NewValue      = true.ToString(),
                    OriginalValue = false.ToString(),
                    PropertyName  = nameof(deletable.IsDeleted)
                });
            }
        }
        public async Task Can_skip_tracking_of_property()
        {
            var options = new DbContextOptionsBuilder <TestTrackerContext>()
                          .UseSqlServer(TestConnectionString)
                          .Options;

            string username = rdg.Get <string>();

            //add enitties
            var entity = new ModelWithSkipTracking {
                TrackedProperty = Guid.NewGuid(), UnTrackedProperty = rdg.Get <string>()
            };

            using (TestTrackerContext ttc = new TestTrackerContext(options))
            {
                ttc.ModelWithSkipTrackings.Add(entity);
                await ttc.SaveChangesAsync(username, CancellationToken.None);

                //assert enity added
                entity.Id.AssertIsNotZero();

                //assert addtion
                entity.AssertAuditForAddition(ttc, entity.Id, username,
                                              x => x.TrackedProperty,
                                              x => x.Id);
            }
        }
Example #3
0
        public void should_be_able_to_delete()
        {
            EntityTracker.TrackAllProperties <TrackedModelWithMultipleProperties>()
            .Except(x => x.IsSpecial);

            TrackedModelWithMultipleProperties existingModel = new TrackedModelWithMultipleProperties();

            var newModel = new TrackedModelWithMultipleProperties
            {
                Id = existingModel.Id
            };

            using (TestTrackerContext newContextInstance = GetNewContextInstance())
            {
                newContextInstance.TrackedModelWithMultipleProperties.Attach(newModel);
                newContextInstance.Entry(newModel).State = EntityState.Deleted;

                newContextInstance.SaveChanges();

                existingModel.AssertAuditForDeletion(newContextInstance, newModel.Id,
                                                     null,
                                                     model => model.Id,
                                                     model => model.Name,
                                                     model => model.StartDate,
                                                     model => model.Value,
                                                     model => model.Description
                                                     );
            }
        }
        public void Should_Log_EmptyProperties_When_Configured_WhileDeleting()
        {
            var options = new DbContextOptionsBuilder <TestTrackerContext>()
                          .UseSqlServer(TestConnectionString)
                          .Options;

            //arrange
            EntityTracker.TrackAllProperties <TrackedModelWithMultipleProperties>();
            GlobalTrackingConfig.TrackEmptyPropertiesOnAdditionAndDeletion = true;

            var entity = new TrackedModelWithMultipleProperties();

            using (TestTrackerContext ttc = new TestTrackerContext(options))
            {
                ttc.TrackedModelWithMultipleProperties.Add(entity);
                ttc.SaveChanges();

                //act
                ttc.TrackedModelWithMultipleProperties.Remove(entity);
                ttc.SaveChanges();

                //assert
                entity.AssertAuditForDeletion(ttc, entity.Id, null,
                                              x => x.Id,
                                              x => x.Description,
                                              x => x.IsSpecial,
                                              x => x.Name,
                                              x => x.StartDate,
                                              x => x.Value);
            }
        }
        public void Can_track_deletion()
        {
            var options = new DbContextOptionsBuilder <TestTrackerContext>()
                          .UseSqlServer(TestConnectionString)
                          .Options;

            string description = rdg.Get <string>();
            string userName    = rdg.Get <string>();

            //add
            NormalModel normalModel = new NormalModel();

            normalModel.Description = description;
            using (TestTrackerContext ttc = new TestTrackerContext(options))
            {
                ttc.NormalModels.Add(normalModel);
                ttc.SaveChanges(userName);

                //remove
                ttc.NormalModels.Remove(normalModel);
                ttc.SaveChanges(userName);

                normalModel.AssertAuditForDeletion(ttc, normalModel.Id, userName,
                                                   x => x.Description,
                                                   x => x.Id);
            }
        }
        public void Can_track_deletion_when_state_changed()
        {
            var options = new DbContextOptionsBuilder <TestTrackerContext>()
                          .UseSqlServer(TestConnectionString)
                          .Options;

            string description = rdg.Get <string>();

            //add
            NormalModel normalModel = new NormalModel();

            normalModel.Description = description;
            using (TestTrackerContext ttc = new TestTrackerContext(options))
            {
                ttc.NormalModels.Add(normalModel);
                ttc.SaveChanges();

                //remove
                ttc.Entry(normalModel).State = EntityState.Deleted;
                ttc.SaveChanges();

                //assert
                normalModel.AssertAuditForDeletion(ttc, normalModel.Id, null,
                                                   x => x.Description,
                                                   x => x.Id);
            }
        }
Example #7
0
        public void Should_Be_Soft_Deleted()
        {
            GlobalTrackingConfig.SetSoftDeletableCriteria <ISoftDeletable>(x => x.IsDeleted);

            SoftDeletableModel entity = new SoftDeletableModel();

            SoftDeletableModel newEntity = new SoftDeletableModel
            {
                Id          = entity.Id,
                Description = entity.Description
            };

            using (TestTrackerContext newContext2 = GetNewContextInstance())
            {
                newEntity.IsDeleted = true;
                newContext2.Entry(newEntity).State = EntityState.Modified;
                newContext2.SaveChanges();

                newEntity.AssertAuditForSoftDeletion(newContext2, newEntity.Id, null,
                                                     new AuditLogDetail
                {
                    PropertyName  = nameof(entity.IsDeleted),
                    OriginalValue = false.ToString(),
                    NewValue      = true.ToString()
                });
            }
        }
Example #8
0
        public void Should_Be_Able_To_Update()
        {
            NormalModel entity = new NormalModel();

            NormalModel newEntity = new NormalModel
            {
                Id          = entity.Id,
                Description = rdg.Get <string>()
            };

            using (TestTrackerContext newContext2 = GetNewContextInstance())
            {
                newContext2.NormalModels.Attach(newEntity);
                newContext2.Entry(newEntity).State = EntityState.Modified;
                newContext2.SaveChanges();

                newEntity.AssertAuditForModification(newContext2, newEntity.Id, null,
                                                     new AuditLogDetail
                {
                    NewValue      = newEntity.Description,
                    OriginalValue = entity.Description,
                    PropertyName  = nameof(NormalModel.Description)
                });
            }
        }
Example #9
0
        public async Task ShouldAddSingleMetadata_WhenSingleMetadataIsProvided_Async()
        {
            var options = new DbContextOptionsBuilder <TestTrackerContext>()
                          .UseSqlServer(TestConnectionString)
                          .Options;

            using (TestTrackerContext ttc = new TestTrackerContext(options))
            {
                ttc.ConfigureMetadata(m =>
                {
                    m.IpAddress = "192.168.2.23";
                });

                EntityTracker.TrackAllProperties <POCO>();
                POCO entity = new POCO();

                ttc.POCOes.Add(entity);
                await ttc.SaveChangesAsync("bilal");

                entity.AssertAuditForAddition(ttc, entity.Id, "bilal",
                                              x => x.Color, x => x.Height, x => x.StartTime, x => x.Id);

                entity.AssertMetadata(ttc, entity.Id, new Dictionary <string, string>
                {
                    ["IpAddress"] = "192.168.2.23"
                });
            }
        }
Example #10
0
        public void Can_recognise_global_tracking_indicator_when_enabled()
        {
            var options = new DbContextOptionsBuilder <TestTrackerContext>()
                          .UseSqlServer(TestConnectionString)
                          .Options;

            EntityTracker
            .TrackAllProperties <POCO>();

            POCO model = new POCO
            {
                Color     = "Red",
                Height    = 67.4,
                StartTime = new DateTime(2015, 5, 5)
            };

            using (TestTrackerContext ttc = new TestTrackerContext(options))
            {
                ttc.POCOes.Add(model);
                ttc.SaveChanges();

                model.AssertAuditForAddition(ttc, model.Id, null,
                                             x => x.Color,
                                             x => x.Id,
                                             x => x.Height,
                                             x => x.StartTime);
            }
        }
Example #11
0
        public void ShouldNotAddMetadata_WhenValueIsNull()
        {
            var options = new DbContextOptionsBuilder <TestTrackerContext>()
                          .UseSqlServer(TestConnectionString)
                          .Options;

            using (TestTrackerContext ttc = new TestTrackerContext(options))
            {
                ttc.ConfigureMetadata(m =>
                {
                    m.IpAddress = "192.168.2.23";
                    m.Country   = null;
                    m.Device    = string.Empty;
                });

                EntityTracker.TrackAllProperties <POCO>();
                POCO entity = new POCO();

                ttc.POCOes.Add(entity);
                ttc.SaveChanges();

                entity.AssertAuditForAddition(ttc, entity.Id, null,
                                              x => x.Color, x => x.Height, x => x.StartTime, x => x.Id);

                entity.AssertMetadata(ttc, entity.Id, new Dictionary <string, string>
                {
                    ["IpAddress"] = "192.168.2.23",
                    ["Device"]    = string.Empty
                });
            }
        }
        public void Can_track_composite_keys()
        {
            var options = new DbContextOptionsBuilder <TestTrackerContext>()
                          .UseSqlServer(TestConnectionString)
                          .Options;

            string key1     = rdg.Get <string>();
            string key2     = rdg.Get <string>();
            string userName = rdg.Get <string>();
            string descr    = rdg.Get <string>();

            ModelWithCompositeKey entity = new ModelWithCompositeKey();

            entity.Description = descr;
            entity.Key1        = key1;
            entity.Key2        = key2;

            using (TestTrackerContext ttc = new TestTrackerContext(options))
            {
                ttc.ModelWithCompositeKeys.Add(entity);
                ttc.SaveChanges(userName);

                string expectedKey = $"[{key1},{key2}]";

                entity.AssertAuditForAddition(ttc, expectedKey, userName,
                                              x => x.Description,
                                              x => x.Key1,
                                              x => x.Key2);
            }
        }
        public async Task Can_get_all_logs()
        {
            var options = new DbContextOptionsBuilder <TestTrackerContext>()
                          .UseSqlServer(TestConnectionString)
                          .Options;

            string      descr = rdg.Get <string>();
            NormalModel model = new NormalModel();

            model.Description = descr;

            using (TestTrackerContext ttc = new TestTrackerContext(options))
            {
                ttc.NormalModels.Add(model);
                await ttc.SaveChangesAsync(rdg.Get <string>());

                model.Id.AssertIsNotZero();

                IEnumerable <AuditLog> logs = ttc.GetLogs("TrackerEnabledDbContext.Common.Tests.Models.NormalModel")
                                              .AssertCountIsNotZero("logs not found");

                AuditLog lastLog = logs.LastOrDefault().AssertIsNotNull("last log is null");

                IEnumerable <AuditLogDetail> details = lastLog.LogDetails
                                                       .AssertIsNotNull("log details is null")
                                                       .AssertCountIsNotZero("no log details found");
            }
        }
Example #14
0
        public async Task ShouldCreateUnDeletedLogForMultiplePropertiesChanged()
        {
            var options = new DbContextOptionsBuilder <TestTrackerContext>()
                          .UseSqlServer(TestConnectionString)
                          .Options;

            string oldDescription = rdg.Get <string>();
            string newDescription = rdg.Get <string>();

            var deletable = new SoftDeletableModel
            {
                Description = oldDescription
            };

            using (TestTrackerContext ttc = new TestTrackerContext(options))
            {
                ttc.Set <SoftDeletableModel>().Attach(deletable);
                ttc.Entry(deletable).State = EntityState.Added;
                await ttc.SaveChangesAsync();

                deletable.AssertAuditForAddition(ttc, deletable.Id, null, x => x.Id, x => x.Description);

                deletable.IsDeleted = true;
                await ttc.SaveChangesAsync();

                deletable.AssertAuditForSoftDeletion(ttc, deletable.Id, null,
                                                     new AuditLogDetail
                {
                    PropertyName  = nameof(deletable.IsDeleted),
                    OriginalValue = false.ToString(),
                    NewValue      = true.ToString()
                });

                deletable.IsDeleted   = false;
                deletable.Description = newDescription;
                await ttc.SaveChangesAsync();

                deletable.AssertAuditForUndeletion(ttc, deletable.Id, null,
                                                   new AuditLogDetail
                {
                    PropertyName  = nameof(deletable.IsDeleted),
                    OriginalValue = true.ToString(),
                    NewValue      = false.ToString()
                },
                                                   new AuditLogDetail
                {
                    PropertyName  = nameof(deletable.Description),
                    OriginalValue = oldDescription,
                    NewValue      = newDescription
                });
            }
        }
Example #15
0
        private void InsertFakeLegacyLog()
        {
            var options = new DbContextOptionsBuilder <TestTrackerContext>()
                          .UseSqlServer(TestConnectionString)
                          .Options;

            var log = new AuditLog
            {
                TypeFullName = "ModelWithCustomTableAndColumnNames",
                EventType    = EventType.Added,
                RecordId     = rdg.Get <int>().ToString(),
                EventDateUTC = rdg.Get <DateTime>(),
                UserName     = ""
            };

            var magnitudeLogDetail = new AuditLogDetail
            {
                Log           = log,
                NewValue      = rdg.Get <string>(),
                OriginalValue = rdg.Get <string>(),
                PropertyName  = "MagnitudeOfForce"
            };

            var directionLogDetail = new AuditLogDetail
            {
                Log           = log,
                NewValue      = rdg.Get <int>().ToString(),
                OriginalValue = rdg.Get <int>().ToString(),
                PropertyName  = "Direction"
            };

            var subjectLogDetail = new AuditLogDetail
            {
                Log           = log,
                NewValue      = rdg.Get <string>(),
                OriginalValue = rdg.Get <string>(),
                PropertyName  = "Subject"
            };

            using (TestTrackerContext ttc = new TestTrackerContext(options))
            {
                ttc.AuditLogs.Add(log);
                ttc.AuditLogDetails.Add(magnitudeLogDetail);
                ttc.AuditLogDetails.Add(directionLogDetail);
                ttc.AuditLogDetails.Add(subjectLogDetail);

                ttc.SaveChanges();
            }
        }
        public async Task Can_save_async()
        {
            var options = new DbContextOptionsBuilder <TestTrackerContext>()
                          .UseSqlServer(TestConnectionString)
                          .Options;

            NormalModel model = new NormalModel();

            using (TestTrackerContext ttc = new TestTrackerContext(options))
            {
                ttc.Entry(model).State = EntityState.Added;
                await ttc.SaveChangesAsync();
            }
            model.Id.AssertIsNotZero();
        }
        public void Can_save_model()
        {
            var options = new DbContextOptionsBuilder <TestTrackerContext>()
                          .UseSqlServer(TestConnectionString)
                          .Options;

            NormalModel model = new NormalModel();

            using (TestTrackerContext ttc = new TestTrackerContext(options))
            {
                ttc.NormalModels.Add(model);
                ttc.SaveChanges();
            }
            model.Id.AssertIsNotZero();
        }
        public void Can_save_when_entity_state_changed()
        {
            var options = new DbContextOptionsBuilder <TestTrackerContext>()
                          .UseSqlServer(TestConnectionString)
                          .Options;

            NormalModel model = new NormalModel();

            using (TestTrackerContext ttc = new TestTrackerContext(options))
            {
                ttc.Entry(model).State = EntityState.Added;
                ttc.SaveChanges();
            }
            model.Id.AssertIsNotZero();
        }
        public void Can_use_default_username()
        {
            var options = new DbContextOptionsBuilder <TestTrackerContext>()
                          .UseSqlServer(TestConnectionString)
                          .Options;

            using (TestTrackerContext ttc = new TestTrackerContext(options))
            {
                ttc.ConfigureUsername("rahul");

                NormalModel model = new NormalModel();
                ttc.NormalModels.Add(model);
                ttc.SaveChanges();
                model.Id.AssertIsNotZero();
                model.AssertAuditForAddition(ttc, model.Id, "rahul", x => x.Id, x => x.Description);
            }
        }
        public void Can_track_navigational_property_change()
        {
            var options = new DbContextOptionsBuilder <TestTrackerContext>()
                          .UseSqlServer(TestConnectionString)
                          .Options;

            //add enitties
            var parent1 = new ParentModel();
            var child   = new ChildModel {
                Parent = parent1
            };

            using (TestTrackerContext ttc = new TestTrackerContext(options))
            {
                ttc.ChildModels.Add(child);
                ttc.SaveChanges();

                child.Id.AssertIsNotZero();   //assert child saved
                parent1.Id.AssertIsNotZero(); //assert parent1 saved

                //save parent 2
                var parent2 = new ParentModel();
                ttc.ParentModels.Add(parent2);
                ttc.SaveChanges();

                parent2.Id.AssertIsNotZero(); //assert parent2 saved

                //change parent
                child.Parent = parent2;
                ttc.SaveChanges();

                AuditLogDetail[] expectedLog = new List <AuditLogDetail>
                {
                    new AuditLogDetail
                    {
                        NewValue      = parent2.Id.ToString(),
                        OriginalValue = parent1.Id.ToString(),
                        PropertyName  = "ParentId"
                    }
                }.ToArray();

                //assert change
                child.AssertAuditForModification(ttc, child.Id, null, expectedLog);
            }
        }
        public void Can_recognise_context_tracking_indicator_when_disabled()
        {
            var options = new DbContextOptionsBuilder <TestTrackerContext>()
                          .UseSqlServer(TestConnectionString)
                          .Options;

            NormalModel model = new NormalModel();

            using (TestTrackerContext ttc = new TestTrackerContext(options))
            {
                ttc.NormalModels.Add(model);

                ttc.TrackingEnabled = false;
                ttc.SaveChanges();

                model.AssertNoLogs(ttc, model.Id);
            }
        }
        public void Can_Create_AuditLogDetail_ForAddedEntity_WithoutQueryingDatabase()
        {
            var options = new DbContextOptionsBuilder <TestTrackerContext>()
                          .UseSqlServer(TestConnectionString)
                          .Options;

            NormalModel model = new NormalModel();

            using (TestTrackerContext ttc = new TestTrackerContext(options))
            {
                ttc.NormalModels.Add(model);
                ttc.ChangeTracker.DetectChanges();
                var entry   = ttc.ChangeTracker.Entries().First();
                var auditor = new AdditionLogDetailsAuditor(entry, null);

                var auditLogDetails = auditor.CreateLogDetails().ToList();
            }
        }
Example #23
0
        public void Should_Be_able_to_insert()
        {
            var entity = new NormalModel
            {
                Description = rdg.Get <string>()
            };

            using (TestTrackerContext ttc = GetNewContextInstance())
            {
                ttc.NormalModels.Add(entity);
                //ttc.Entry(entity).State = EntityState.Added;

                ttc.SaveChanges();

                entity.AssertAuditForAddition(ttc, entity.Id, null,
                                              x => x.Id,
                                              x => x.Description);
            }
        }
        public void Can_track_complex_type_property_change()
        {
            var options = new DbContextOptionsBuilder <TestTrackerContext>()
                          .UseSqlServer(TestConnectionString)
                          .Options;

            //add enity
            string oldDescription = rdg.Get <string>();
            string newDescription = rdg.Get <string>();

            //only set one of the properties on the complex type
            var complexType = new ComplexType {
                Property1 = oldDescription
            };
            var entity = new ModelWithComplexType {
                ComplexType = complexType
            };

            using (TestTrackerContext ttc = new TestTrackerContext(options))
            {
                ttc.Entry(entity).State = EntityState.Added;
                ttc.SaveChanges();

                //modify entity
                entity.ComplexType.Property1 = newDescription;
                ttc.SaveChanges();

                AuditLogDetail[] expectedLog = new List <AuditLogDetail>
                {
                    new AuditLogDetail
                    {
                        NewValue      = newDescription,
                        OriginalValue = oldDescription,
                        PropertyName  = "ComplexType_Property1"
                    }
                }.ToArray();

                //assert
                entity.AssertAuditForModification(ttc, entity.Id, null, expectedLog);
            }
        }
Example #25
0
        public void InitializeTest()
        {
            var options = new DbContextOptionsBuilder <TestTrackerContext>()
                          .UseSqlServer(TestConnectionString)
                          .Options;

            using (TestTrackerContext ttc = new TestTrackerContext(options))
            {
                _migration = new LogDataMigration(ttc);
            }

            _migration.AuditLogUpdated += (sender, args) =>
            {
                Debug.WriteLine($"\tAuditLog[{args.RecordId}] updated: {args.OldName} -> {args.NewName}");
            };

            _migration.AuditLogDetailUpdated += (sender, args) =>
            {
                Debug.WriteLine($"\t\tAuditLogDetail[{args.RecordId}] updated: {args.OldName} -> {args.NewName}");
            };
        }
        public void Can_track_addition_when_usermane_not_provided()
        {
            var options = new DbContextOptionsBuilder <TestTrackerContext>()
                          .UseSqlServer(TestConnectionString)
                          .Options;

            string randomText = rdg.Get <string>();

            NormalModel normalModel = new NormalModel();

            normalModel.Description = randomText;
            using (TestTrackerContext ttc = new TestTrackerContext(options))
            {
                ttc.NormalModels.Add(normalModel);
                ttc.SaveChanges();

                normalModel.AssertAuditForAddition(ttc, normalModel.Id, null,
                                                   x => x.Description,
                                                   x => x.Id);
            }
        }
        public void Can_Create_AuditLogDetail_ForModifiedEntity_WithoutQueryingDatabase()
        {
            var options = new DbContextOptionsBuilder <TestTrackerContext>()
                          .UseSqlServer(TestConnectionString)
                          .Options;

            NormalModel model = new NormalModel();

            using (TestTrackerContext ttc = new TestTrackerContext(options))
            {
                ttc.NormalModels.Add(model);
                ttc.SaveChanges();
                model.Description += rdg.Get <string>();
                ttc.ChangeTracker.DetectChanges();
                var entry         = ttc.ChangeTracker.Entries().First();
                var valuesWrapper = new DbEntryValuesWrapper(entry);
                var auditor       = new ChangeLogDetailsAuditor(entry, null, valuesWrapper);

                var auditLogDetails = auditor.CreateLogDetails().ToList();
            }
        }
Example #28
0
        public void ShouldCreateSoftDeleteLogForMultiplePropertiesChanged()
        {
            var options = new DbContextOptionsBuilder <TestTrackerContext>()
                          .UseSqlServer(TestConnectionString)
                          .Options;

            //create a softdeletable entity and soft delete it
            var deletable = new SoftDeletableModel();

            using (TestTrackerContext ttc = new TestTrackerContext(options))
            {
                ttc.SoftDeletableModels.Add(deletable);

                //save it to database
                ttc.SaveChanges();

                deletable.AssertAuditForAddition(ttc, deletable.Id, null, x => x.Id);

                //soft delete entity
                deletable.IsDeleted   = true;
                deletable.Description = rdg.Get <string>();

                //save changes
                ttc.SaveChanges();

                //assert for soft deletion
                deletable.AssertAuditForSoftDeletion(ttc, deletable.Id, null, new AuditLogDetail
                {
                    NewValue      = true.ToString(),
                    OriginalValue = false.ToString(),
                    PropertyName  = nameof(deletable.IsDeleted)
                },
                                                     new AuditLogDetail
                {
                    NewValue      = deletable.Description,
                    OriginalValue = null,
                    PropertyName  = nameof(deletable.Description)
                });
            }
        }
        public void Can_save_child_to_parent()
        {
            var options = new DbContextOptionsBuilder <TestTrackerContext>()
                          .UseSqlServer(TestConnectionString)
                          .Options;

            var child  = new ChildModel();
            var parent = new ParentModel();

            using (TestTrackerContext ttc = new TestTrackerContext(options))
            {
                ttc.ParentModels.Add(parent);
                ttc.SaveChanges();

                child.Parent = parent;
                ttc.ChildModels.Add(child);
                ttc.SaveChanges();
            }

            child.Id.AssertIsNotZero();
            parent.Id.AssertIsNotZero();
        }
        public void Shoud_Not_Log_EmptyProperties_OnAddition()
        {
            var options = new DbContextOptionsBuilder <TestTrackerContext>()
                          .UseSqlServer(TestConnectionString)
                          .Options;

            //arrange
            EntityTracker.TrackAllProperties <TrackedModelWithMultipleProperties>();
            var entity = new TrackedModelWithMultipleProperties();

            using (TestTrackerContext ttc = new TestTrackerContext(options))
            {
                ttc.TrackedModelWithMultipleProperties.Add(entity);

                //act
                ttc.SaveChanges();

                //assert
                entity.AssertAuditForAddition(ttc, entity.Id, null,
                                              x => x.Id);
            }
        }