如何使用模拟存储库来测试 CRUD?

How to use mocked repository for testing CRUD?

我知道有很多这样的 questions/articles 我已经读了很多遍了,但我还是卡住了。

我有一个非常简单的代码。 Database=>Entity Framwork=>Repository=>Logic=>Display and now tests。我的问题是我找不到任何帮助来测试我的 CRUD 操作。我只有以下说明:"Test with mocked repository"。所以下面的就没问题了

    [Test]
    public void TestThatReadCrewWorks()
    {
        CrewLogic logic = new CrewLogic();
        var result = logic.LReadCrew(102);
        Assert.That(result.Name, Is.EqualTo("Test Joe"));
    }

如何使用我的存储库(使用 dbcontext)进行独立测试,而不为测试 dll 提供连接字符串?我试过了...

    [Test]
    public void TestThatCreatingCrewWorks2()
    {
        DbContext ctx;
        CrewRepository newc = new CrewRepository(ctx);
    }

...从这里完全黑暗。 dbcontext 在这里应该是什么?

任何帮助,甚至 link 都非常适合。谢谢。

编辑:澄清

public abstract class Repository<T> : IRepository<T>
    where T : class
{
    protected DbContext ctx;

    public Repository(DbContext ctx)
    {
        this.ctx = ctx;
    }

    public T Read(int id)
    {
        return this.ctx.Set<T>().Find(id);
    }
    //...and other crud operations
 }

我有这个语法。我如何编写取决于此通用 DBcontext 而不是我的实际数据库的测试。我应该以某种方式创建假 class 吗?

您的存储库只是包装 DbContextDbContext 本身在发布前已经过 Microsoft 测试。无需测试 DbContext 是否按照其设计目的进行。

要测试存储库是否按预期使用上下文,您需要使用实际上下文进行集成测试。模拟 DbContext 或使用内存中的 DbContext。无论哪种方式,您的测试都会给人一种错误的安全感,因为您基本上是在测试已经由其开发人员测试过的包装代码。

例如你的 return this.ctx.Set<T>().Find(id); 在基本存储库中。该行中的所有内容都是 DbContext 相关的,不值得你测试它是否做了它应该做的事情。

例如,查看相同存储库方法的以下测试

[Test]
public void CrewWorks_Should_Find_By_Id() {
    //Arrange
    int expectedId = 102;
    string expectedName = "Test Joe";
    Crew expected = new Crew {
        Id = expectedId,
        Name = "Test Joe"
    };
    Mock<DbContext> ctxMock = new Mock<DbContext>();
    ctxMock
        .Setup(_ => _.Set<Crew>().Find(expcetedId))
        .Returns(expected);
    DbContext ctx = ctxMock.Object;
    CrewRepository subject = new CrewRepository(ctx);

    //Act
    Crew actual = subject.Read(expectedId);

    //Assert
    Assert.That(actual, Is.EqualTo(expected));
}

以上测试验证了包装 DbContext 相关调用的预期行为,并没有真正提供太多安全性,因为它基本上是在测试包装代码是否被调用。

理想情况下,存储库应该被模拟并用于测试更高级别的逻辑

[Test]
public void TestThatReadCrewWorks() {
    int expectedId = 102;
    string expectedName = "Test Joe";
    Crew expected = new Crew {
        Id = expectedId,
        Name = "Test Joe"
    };
    //Assuming abstraction of specific repository 
    //  interface ICrewPrepsitory: IRepository<Crew> { }
    ICrewPrepsitory repository = Mock.Of<ICrewPrepsitory>(_ =>
        _.Read(expectedId) == expected
    );

    CrewLogic logic = new CrewLogic(repository); //assuming injection

    //Act
    var actual = logic.LReadCrew(expectedId);

    //Assert
    Assert.That(actual.Name, Is.EqualTo(expectedName));
    //...other assertions
}