我正在使用Entity Framework Core对使用内存数据库制作的应用程序进行单元测试,但是我遇到了我的一个功能问题。到目前为止,我已经测试过通过ID获取游戏(它可以工作),将游戏添加到集合中(它也可以工作)以及更新集合中的游戏(它不工作)。
功能代码:
[TestMethod()]
public async Task UpdateGameAsyncTest()
{
//Arrange
await CreateDb();
GameDto gameDto = new GameDto()
{
Id = 2,
Team1 = "PSG",
Team2 = "AZ",
Date = DateTime.UtcNow
};
//Act
var id = await _gameService2.UpdateGameAsync(gameDto);
var game = await _gameService2.GetGameAsync(id);
//Assert
Assert.AreEqual("AZ", game.Team1);
}
我的服务层中的UpdateGameAsync():
public async Task<int> UpdateGameAsync(GameDto game)
{
var gameEntity = game.ToEntity();
return await _gameRepository.UpdateGameAsync(gameEntity);
}
我的存储库层中的UpdateGameAsync():
public async Task<int> UpdateGameAsync(Game game)
{
if (game.Result != null)
{
if (game.Result.Length == 3 && game.Result.Substring(1, 1) == "-")
{
game.typeResult = await CheckTypeResult(game.Result);
}
}
_dbContext.Games.Update(game);
return await AutoSaveChangesAsync();
}
CreateDb():
public async Task CreateDb()
{
var options = new DbContextOptionsBuilder<StrikeNetDbContext>()
.UseInMemoryDatabase(databaseName: Guid.NewGuid().ToString())
.EnableSensitiveDataLogging()
.UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking)
.Options;
var dbContext = new StrikeNetDbContext(options);
if (await dbContext.Games.CountAsync() <= 0)
{
Game g1 = new Game()
{
Id = 1,
Team1 = "FCB",
Team2 = "BVB",
Date = DateTime.UtcNow
};
Game g2 = new Game()
{
Id = 2,
Team1 = "PSG",
Team2 = "PSV",
Date = DateTime.UtcNow
};
Game g3 = new Game()
{
Id = 3,
Team1 = "Ajax",
Team2 = "Feyenoord",
Date = DateTime.UtcNow
};
dbContext.Games.Add(g1);
dbContext.Games.Add(g2);
dbContext.Games.Add(g3);
await dbContext.SaveChangesAsync();
}
var gameRepository = new GameRepository(dbContext);
_gameService2 = new GameService(gameRepository);
}
[运行测试时,我遇到错误:“无法跟踪实体类型'Game'的实例,因为已经跟踪了另一个键值为'{Id:2}'的实例。在附加现有实体时,请确保只能附加一个具有给定键值的实体实例。“
出于比较目的,这是确实起作用的添加功能:
[TestMethod()]
public async Task AddGameAsyncTest()
{
//Arrange
await CreateDb();
GameDto game = new GameDto()
{
Team1 = "Juve",
Team2 = "Real",
Date = DateTime.UtcNow
};
//Act
var id = await _gameService2.AddGameAsync(game);
var expected = await _gameService2.GetGameAsync(id);
//Assert
Assert.AreEqual("Juve", expected.Team1);
}
我已经尝试了几种方法来回答所提出的类似问题,但是它们都不适合我。我的存储库en服务的范围仅限于Startup.cs,并且在createdb()函数als中分离实体似乎不起作用。还有其他想法吗?
我认为它来自您的UpdateGameAsync
方法。如文档所述,如果在内部调用EF Update
,则尝试跟踪实体
Begins tracking the given entity in the Microsoft.EntityFrameworkCore.EntityState.Modified
但是,我认为您的实体已经被跟踪,因为我觉得您在CreateDb
中使用了相同的dbContext,并且此行开始了对您的实体的跟踪:
dbContext.Games.Add(g2);
您可以检查您的存储库中是否跟踪您的实体:
_context.Games.Local.Any(g => g.Id == entity.Id)
如果已经被跟踪,则无需调用EF Update()
。
顺便说一句,如果您的实际案例没有使用相同的DbContext进行数据初始化和读取数据,我建议您使用另一个上下文,以确保您可以正常使用。