1

I am making a MSTest project of my app created with Data-driven strategy. Now, I would like to mock the database using interface. But the DB Entity is automatically generated, so my modification for DI will be destroyed when entity was updated.

Should I give up testing with a mock and access the actual DB every time?

(Update 2022/01/28) I am thinking for compromise: rather than accessing DB entity directly on the model, I would make service facades that on the one class handles DB (for production usage), while the other just works itself.

Short crude examples here:

public interface IMemberDatabaseService
{
    Member Search(string name);
    void Create(MemberModel model);
}

public class MemberDatabaseService : IMemberDatabaseService, IDisposable
{
    private AutomaticallyGeneratedDBContext Con = new();
    public Member Search(string name)
    {
        return Con.Member.SingleOrDefault(mb => mb.Name == name);
    }

    public void Create(MemberModel model)
    {
        Member member = Convert(model);
        Con.Member.Add(model);
        Con.SaveChanges();
    }

    private static Member Convert(MemberModel model)
    {
        // convert model to Member
    }
    // Dispose pattern here...
}

public class MemberTestService : IMemberDatabaseService, IDisposable
{
    private static List<Member> MemberList = new();
    public Member Search(string name)
    {
        return name == "John Doe" ? new Member{ Name = name, ...} : null;
    }

    public void Create(MemberModel model)
    {
        Member member = Convert(model); // convert model to Member
        MemberList.Add(model);
    }

    private static Member Convert(MemberModel model)
    {
        // convert model to Member
    }
    // Dispose pattern here...
}

The drawback is I cannot test the LINQ portion or conflict handling without connecting the DB.

1 Answers1

0

You will need to add specific detail about what your implementation looks like.

Mocking DbContexts/DbSets is possible, but arguably a fair bit of work and ugly to work with. Unit testing is one good argument for implementing a Repository pattern to serve as a boundary for the mocks, but if you're past the point where something like that can be implemented, a simpler solution can be to point your DbContext at an in-memory database that is seeded with suitable test data.

The downside is that most test frameworks accommodate running tests in parallel and not necessarily in order so you need to ensure each test's data row dependencies are safely isolated from each other to ensure you don't get intermittent failures due to one test tampering with data that another test relies on.

Steve Py
  • 26,149
  • 3
  • 25
  • 43
  • `DbContext` already implements repository pattern. Not sure why to add another on top of it. According to in-memory database, you can create new one for each test. It is only a matter of having different database name per test. That will create isolation and shouldn't be that hard to achieve it. Only problem with in-memory database is that references between entities/tables are not validated. – dropoutcoder Jan 27 '22 at 21:29
  • Because mocking a repository is a far simpler task than attempting to mock a DbContext and it's DbSets. A mocked repository method merely has to return an `IQueryable`/`IEnumerable` or such pointed at a `List` populated with your test stub data for the known state. (or return an empty list / throw an exception, depending on the scenario you want to test) – Steve Py Jan 27 '22 at 22:20
  • In data driven testing exactly this is not simpler, but harder as you need to write same test many times with different input values and setup many mocks with different results to properly test it. Fundamental problem is never-ending sticking to repository instead of moving to operation based execution. Which if you want you can mock as you are defining those in your code. Not mentioning it is far more flexible, than rigid repository with fixed methods. I guess our disagreement is based on the way we develop things. – dropoutcoder Jan 28 '22 at 00:23
  • In data driven testing exactly this is not simpler, but harder as you need to write same test many times with different input values and setup many mocks with different results to properly test it. Fundamental problem is never-ending sticking to repository instead of moving to operation based execution. Which if you want you can mock as you are defining those in your code. Not mentioning it is far more flexible, than rigid repository with fixed methods. I guess our disagreement is based on the way we develop things. – dropoutcoder Jan 28 '22 at 00:23
  • Which is why I also suggested the in-memory DB as an alternative. Software development is not about pounding square pegs into holes of every shape. Different requirements call for different solutions. Mocks are a means for Unit Testing: testing business logic. The point there is to decouple that logic from the data so that it can be executed often and quickly. Testing functionality that is dependent heavily on the data state falls under integration testing, in which case you generally use a known data state to execute against. Depending on the objective, the OP likely doesn't need mocks. – Steve Py Jan 28 '22 at 01:06