Xunit - 如何使用Moq和EF Core作為身份主鍵

c# entity-framework-core moq xunit

我試圖使用AutoMoq和Xunit for Inserting功能自動化我的UnitTesting。

但我一直認為我無法在KeyColumn中插入一個值,如下所示。 EnrolmentRecordID是我的SQL數據庫中的IdentityColumn,其值在插入時自動生成。

消息:Microsoft.EntityFrameworkCore.DbUpdateException:更新條目時發生錯誤。有關詳細信息,請參閱內部異常---- System.Data.SqlClient.SqlException:當IDENTITY_INSERT設置為OFF時,無法在表'EN_Schedules'中為identity列插入顯式值。

如果我不使用Moq或者我沒有將數據設置為EnrolmentRecordID列,則可以避免這種情況。但我不知道如何在EnrolmentRecordID中排除EnrolmentRecordID。由於它是關鍵列,因此我也無法將NULLABLE功能設置為該列。

StudentSchedule.cs

public class StudentSchedule
{
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int EnrolmentRecordID { get; set; }

    public string AcademicYearID { get; set; }
    [Display(Name = "Student")]
    public string StudentName { get; set; }

    public string ProposedQual { get; set; }

    [DatabaseGenerated(DatabaseGeneratedOption.Computed)]
    public DateTime? DateCreated { get; set; }
}

AddService

public async Task Add(StudentSchedule model)
{
    await _context.Schedules.AddAsync(model);
    await _context.SaveChangesAsync();
}

XUnitTest

public class TestCommandsSchedule
{
    private ERAppData.Commands.CommandSchedule _command;
    public TestCommandsSchedule()
    {
        _command = new ERAppData.Commands.CommandSchedule(AppsecDBContext.GenerateAppsecDBContext() as ERAppData.DbContexts.AppsecDbContext);
    }

    [Theory]
    [AutoMoqData]
    public async Task Should_Add_Schedule(StudentSchedule model)
    {            
        model.AcademicYearID = "16/17";
        model.DateCreated = null;

        await _command.Add(model);

        Assert.True(model.EnrolmentRecordID > 0);
    }
}

你能幫助我如何使用Moq生成MockObject並測試Add Service嗎?謝謝。

一般承認的答案

這個簡化的例子說明瞭如何將測試對象與具體結構分離,以便可以單獨進行單元測試。

摘要遠離DbContext

public interface IStudenScheduleService : IGenericRepository<StudentSchedule> {
}

public interface IGenericRepository<T> {
    Task<T> AddAsync(T value, CancellationToken cancellationToken = default(CancellationToken));
    Task<int> SaveChangesAsync(CancellationToken cancellationToken = default(CancellationToken));
}

確保實現包裝實際上下文並提供所需的功能。

主題類是否依賴於抽象。

public class CommandSchedule {
    private readonly IStudenScheduleService _context;

    public CommandSchedule(IStudenScheduleService context) {
        this._context = context;
    }

    public async Task Add(StudentSchedule model) {
        await _context.AddAsync(model);
        await _context.SaveChangesAsync();
    }
}

有了這個,可以模擬測試對象的依賴關係並用於執行測試。

[Theory]
[AutoMoqData]
public async Task Should_Add_Schedule(StudentSchedule model)  
   //Arrange
    var expectedId = 0;
    var expectedDate = DateTime.Now;

    var context = new Mock<IStudenScheduleService>();
    context.Setup(_ => _.SaveChangesAsync(It.IsAny<CancellationToken>()))
        .ReturnsAsync(1)
        .Callback(() => {
            model.EnrolmentRecordID = ++expectedId;
            model.DateCreated = expectedDate;
        })
        .Verifiable();

    context.Setup(_ => _.AddAsync(It.IsAny<StudentSchedule>(), It.IsAny<CancellationToken>()))
        .ReturnsAsync((StudentSchedule m, CancellationToken t) => m)
        .Verifiable();

    var _command = new CommandSchedule(context.Object);

    model.AcademicYearID = "16/17";
    model.DateCreated = null;

    //Act
    await _command.Add(model);

    //Assert
    context.Verify();
    Assert.AreEqual(expectedId, model.EnrolmentRecordID);
    Assert.AreEqual(expectedDate, model.DateCreated);
}


Related

許可下: CC-BY-SA with attribution
不隸屬於 Stack Overflow
許可下: CC-BY-SA with attribution
不隸屬於 Stack Overflow