我正在编写单元测试来测试控制器操作,该操作更新EF Core实体。
我使用SQLLite而不是模拟。
我设置了我的数据库如下:
internal static ApplicationDbContext GetInMemoryApplicationIdentityContext()
{
var connection = new SqliteConnection("DataSource=:memory:");
connection.Open();
var options = new DbContextOptionsBuilder<ApplicationDbContext>()
.UseSqlite(connection)
.Options;
var context = new ApplicationDbContext(options);
context.Database.EnsureCreated();
return context;
然后像这样将一个实体添加到数据库中:
private DiaryEntriesController _controller;
private ApplicationDbContext _context;
[SetUp]
public void SetUp()
{
_context = TestHelperMethods.GetInMemoryApplicationIdentityContext();
_controller = new DiaryEntriesController(_context);
}
[Test]
[Ignore("https://dev59.com/llgQ5IYBdhLWcg3w1nfm")]
public async Task EditPost_WhenValid_EditsDiaryEntry()
{
// Arrange
var diaryEntry = new DiaryEntry
{
ID = 1,
Project = new Project { ID = 1, Name = "Name", Description = "Description", Customer = "Customer", Slug = "slug" },
Category = new Category { ID = 1, Name = "Category" },
StartDateTime = DateTime.Now,
EndDateTime = DateTime.Now,
SessionObjective = "objective",
Title = "Title"
};
_context.DiaryEntries.Add(diaryEntry);
await _context.SaveChangesAsync();
var model = AddEditDiaryEntryViewModel.FromDiaryEntryDataEntity(diaryEntry);
model.Actions = "actions";
// Act
var result = await _controller.Edit(diaryEntry.Project.Slug, diaryEntry.ID, AddEditDiaryEntryViewModel.FromDiaryEntryDataEntity(diaryEntry)) as RedirectToActionResult;
// Assert
var retreivedDiaryEntry = _context.DiaryEntries.First();
Assert.AreEqual(model.Actions, retreivedDiaryEntry.Actions);
}
我的控制器方法看起来像这样:
[HttpPost]
[ValidateAntiForgeryToken]
[Route("/projects/{slug}/DiaryEntries/{id}/edit", Name = "EditDiaryEntry")]
public async Task<IActionResult> Edit(string slug, int id, [Bind("ID,CategoryID,EndDate,EndTime,SessionObjective,StartDate,StartTime,Title,ProjectID,Actions,WhatWeDid")] AddEditDiaryEntryViewModel model)
{
if (id != model.ID)
{
return NotFound();
}
if (ModelState.IsValid)
{
var diaryEntryDb = model.ToDiaryEntryDataEntity();
_context.Update(diaryEntryDb);
await _context.SaveChangesAsync();
return RedirectToAction("Details", new { slug = slug, id = id });
}
ViewData["CategoryID"] = new SelectList(_context.Categories, "ID", "Name", model.CategoryID);
ViewData["ProjectID"] = new SelectList(_context.Projects, "ID", "Customer", model.ProjectID);
return View(model);
}
我的问题是在测试时,当我尝试更新实体时,它会出现错误。我收到以下消息:
由于已经跟踪了具有相同键的此类型的另一个实例,因此无法跟踪实体类型“DiaryEntry”的实例。
这段代码在实际生产环境中很好用。但我卡在了测试插入数据后如何停止跟踪,以使生产代码中的数据库上下文不再跟踪插入的实体。
我明白模拟接口到存储库模式的好处,但我真的希望能让这种测试方法可行——将数据插入内存数据库,然后测试是否已在数据库中更新了该数据。
非常感谢任何帮助。
谢谢。
编辑: 我添加了完整的测试代码,以显示我正在使用相同的上下文创建数据库和插入我将控制器实例化的日记条目。