简体   繁体   中英

How to use mocked repository for testing CRUD?

I know there are a lot of these kind of questions/articles and I've read a lot of them multiple times, but I'm still stuck.

I have a very simple code. Database=>Entity Framwork=>Repository=>Logic=>Display and now tests. My problem that I couldn't find any help how to test my CRUD operations. I only have the following instructions: "Test with mocked repository". So the following is out of question.

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

How can I use my repository (which uses dbcontext) to test independently, without giving test dll the connectionstring? I tried...

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

...and from here complete darkness. What should dbcontext be here?

Any help, even link is highly appropriated. Thank you.

edit: clarification

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
 }

I have this syntax. How do I write test which depends on this general DBcontext rather than my actual database. Should I create fake class somehow?

Your repository is simply wrapping DbContext . DbContext on its own has already been tested by Microsoft before being released. No need to test that a DbContext does what it was designed to do.

To test that the repository used the context as expected then you need to do an integration test with an actual context. Either mock the DbContext or use an in-memory DbContext . Either way, your tests will be giving a false sense of security since you are basically testing wrapped code that has already been tested by its developer.

For example your return this.ctx.Set<T>().Find(id); in the base repository. Everything in that line is DbContext related and not worth you testing that is does what it is suppose to do.

For example, look at the following test of that same repository method

[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));
}

The above test verifies expected behavior for the wrapped DbContext related calls and does not really provide much in terms of security since it basically is testing that wrapped code is invoked.

Ideally the repository should be mocked and used to test the logic at higher levels

[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
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM