5

Recently I've started a project for simulating various neural network applications. To handle the considerable amount of data involved I've implemented a SQL-Server back end using the Entity Framework Model first approach.
Additionally I've grown quite fond of the test driven development (TDD) discipline. However in order to do so I need a mock database to run my tests on. After much searching I found multiple solutions both commercial and open source. At this point it's worth noting that I'm quite the novice when it comes to Database related subjects. Consequently I elected to use the msdn described in memory mock for the EF6 framework as described here.

Pff, now we got the background out of the way, here is my question:

I've created my model and generated the database from it. The code generation of the real interface layer is done by the edmx. To unit test I've followed the above described tutorial and adapted the relevant fields to match my database model,. (which can be found https://i.stack.imgur.com/bN9iG.png, unfortunately I dont have the rep to include the image in the post...).
However I don't need all the data for every test, only some subsets. I would like a situation where i can specify in the setup of the test which tables to load an perhaps the depth of loading the dependencies.

The problem I encountered was that the related data was not loaded along with current DBSet when specifying the related foreign key. For example when setting up the data for the Connection set I would like the entries to link to the related data, in this case elements of the Node set:

var context = new TestContext();

context.NodeSet.Add(new Node { NodeID = 1 });
context.NodeSet.Add(new Node { NodeID = 2 });

context.ConnectionSet.Add(new Connection { ConnID = 1, ToNodeID = 1, FromNodeID = 2 });

var conn = context.ConnectionSet.First();
var fromNode = conn.FromNode;
var toNode = conn.ToNode;

In this example the FromNode property of the specified Connection returns null. The desired situation is that the mock has the ability to relate the ToNodeID key to the relevant object. Furthermore I expect that the order of loading is relevant for resolving the key constraints i.a.w. in order to resolve the FromNode field the corresponding Node must exist.

I am open to all suggestions regarding this specific question but also if any of you know a more constructive way to mock an EF6 model first database design.

Thanks in advance!

Bermudian
  • 53
  • 5
  • This is only a suggestion but you could use a subclass of Node instead of base POCO Node and the subclass would have the navigation property implemented manually so that it refers to related class by id. – Wiktor Zychla Feb 05 '14 at 22:24
  • A valid suggestion but I want the mock to realize that relation between the navigation property and the relevant object on itself. Otherwise I would have to manually create subclasses for every table in my database and implement its navigation properties. Thanks for the suggestion, I'll use it as an fall back. – Bermudian Feb 05 '14 at 22:34
  • If you are clever, you can mock the Add method so that whenever you add Node, the Add internally wraps it (using castle proxy or similar) and adds wrapped to the internal collection. I've never tried it and plan to do it soon and also wonder if there are known approaches to this. – Wiktor Zychla Feb 05 '14 at 22:43
  • Don't mock, really. The differences with code running against a live database are just [too many](http://stackoverflow.com/a/13352779/861716). Suppose you get it done. The next challenge may be how to disable lazy loading when it is disabled in the context or when a member is not virtual. Later you start wondering how to fake `DbFunctions`, or account for not supported CLR methods or casts, then..... - Do integration tests (with a test database) where data access is involved, pure unit tests where it isn't. Admittedly, maintaining a test database is hard work, but false green tests are horror. – Gert Arnold Feb 06 '14 at 07:46
  • @GertArnold: false green tests can occur always, if one of your mocks fails for some reason. Either then you accept the fact that mocks **aren't** real implementations or you are against mocking at all. As you said, the lack of proper integration tests could be a problem but making all your tests that access data as integration tests sounds like an overkill ("hard work" as you said). – Wiktor Zychla Feb 06 '14 at 09:14
  • @WiktorZychla False green tests can always occur? If so, the test should be modified to reflect reality more closely. With EF this is a dead end though. But I should add that I've applied limited mocking in my own tests when it matters less how objects are obtained and the focus is at testing business logic units. It's just the easiest way to obtain mocks. However, when data access is pivotal (as in most service methods) I only do integration tests. Matter of taste, maybe. – Gert Arnold Feb 06 '14 at 09:53
  • @GertArnold: this is what we do also, limited mocking of EF if common sense suggests that it doesn't introduce unwanted risks. – Wiktor Zychla Feb 06 '14 at 10:53

1 Answers1

1

After the discussion and rethinking the issue, I believe the easiest approach would be to forget about automatic resolving by ID but rather manually set up references prior to your tests.

In other words, if you have two dbsets, Child and Parent and each child entity points to a single parent so that you have

public class Child
{
   public int ID_PARENT { get; set; }
   public virtual Parent Parent { get; set; }
}

then you set up your mocks with data

var mockedContext = ... ; // create mocked context with mocked DbSets as
                          // shown in the article you refer to

Child c = new Child();

Parent p = new Parent();
c.Parent = p;  // set up the relation manually

mockedContext.Child.Add( c );
mockedContext.Parent.Add( p );

// property resolving works now as you have set it up in an explicit way
// note that IDs are irrelevant
var children = mockedContext.Child.Where( c => c.Parent != null && c.Parent.Name.StartsWith( "n" ) );
Wiktor Zychla
  • 47,367
  • 6
  • 74
  • 106