I'm trying to add unit testing to my projects that use EF6. The TDD approach works fine for simple methods that taken an input and return some output, but I'm not clear on how to make it work for methods that do read/write operations on the database. More specifically, I'm not entirely sure about how to create an in-memory representation of the database (for the test data) and then "mock" the context to point to that in-memory representation.
As an example, please consider the below class (not representative of the actual production code but demonstrates the problem) that reads a file line by line, references a bunch of tables to do some validation and then stores results to two separate database tables -
class Importer {
private repository;
private bool IsValid(string line) {
//Refer to a bunch of database tables and return true or false. Below is just a random code that demonstrates this
if(repository.Context.SomeTable1.Count(t => t.Prop1 == line[2]) > 0 &&
repository.Context.SomeTable2.First(t => t.Prop2 == line[3]).Prop3 != null &&
...
repository.Context.SomeTable10.Last(t => t.Prop5 == line[5]).Prop9 != null)
return true;
return false;
}
public Importer(IRepository repository) { this.repository = repository; }
public void Process(string fileName) {
ImportLog log = new ImportLog();
foreach(var line in GetNextLine(fileName) { //GetNextLine reads the file and yield returns lines
if(IsValid(line)) { //IsValid refers to a bunch of tables and returns true/false
log.Imported++;
FileTable fileTable = new fileTable();
fileTable.Line = line;
repository.Context.FileTables.Add(fileTable);
repository.Context.Entry(fileTable).State = EntityState.Added;
repository.Context.SaveChanges(); //Must save here, can't buffer because the file and lines are too large
}
else { log.Rejected++; }
}
repository.Context.ImportLogs.Add(log);
repository.Context.Entry(log).State = EntityState.Added;
repository.Context.SaveChanges();
}
}
Now, the only real test that verifies that the class is working is to run the Process
method and then check the database to ensure that ImportLog
and FileTable
tables contain correct values for the given file.
This brings us to my question - How do I create an in-memory representation of the database (that contains ImportLog
, FileTable
, SomeTable1 to 10
tables and then point the repository.Context to that in-memory representation? Or am I going about it in a completely wrong manner?
Note: I suppose I could create mock CRUDs in the repository instead of just using the DBContext but that would be a momentous effort because the database has close to 100 tables. Just pointing the DBContext to a mocked database solves the problem most efficiently. Alternatively, I could create a real test database but I'm keeping that option only for if an in-memory database solution is not possible.