views:

546

answers:

2

We use C# and Linq2SQL with a MS SQL Server Database. We have a mockdatacontext to carry out some unit testing. When testing we have discovered two different behaviours depending on whether the "real" or "mock" database is used.

Scenario 1: Real Database

There are 5 records in the database:

db = realDatabase
db.InsertOnSubmit(new record)

var count1 = db.getTable.Count()

db.SubmitChanges()

var count2 = db.getTable.Count()

count1 = 5 count2 = 6

Scenario 2: Mock Database

There are 5 records in the database:

db= mockDatabase

db.InsertOnSubmit(new record)

var count1 = db.getTable.Count()

db.SubmitChanges()

var count2 = db.getTable.Count()

count1 = 6 count2 = 6

*The "mock" database is already aware of the new record before SubmitChanges() is called, so it is included in the count. For testing, we need the two behaviours to be the same.

Has anyone else come across this problem and can you suggest a solution?

A: 

I would guess that your mock database (in memory??) is not transactional and that the InsertOnSubmit method is actually inserting the record.

Alex B
+4  A: 

IMO, it is a common mistake that one tries to simulate in tests. A mock is not a simulator. It should not implement a logic that is similar to the original, it should just return hard coded results.

If the mock behaviour is complex, you end up in testing you mock instead of your business code.

I'm using RhinoMocks, and it would look like this:

// arrange
IList<Record> testdata = new List<Record>() {a, b, c};
db = MockRepository.GenerateMock<IDatabase>();
db.Stub(x => db.getTable).Return(testdata);

// act: call your unit under test

// assert
db.AssertWasCalled(x => x.InsertOnSubmit(Arg<Record>.Is.Anything));
db.AssertWasCalled(x => x.SubmitChanges());

It still returns the same list every time. For many cases, this will be sufficient. You still could return other data on the second getTable call:

db.Stub(x => db.getTable).Return(testdata1);
db.Stub(x => db.getTable).Return(testdata2);

It's always specific to a single test, but this makes it so simple.

Edit:

I have to admit that I'm not familiar with Linq2Sql. The calls that are mocked in my example are Linq2Sql calls, which probably cannot be mocked that easily. You probably need to put it behind an simple DAL interface. Then you mock this interface.

Stefan Steinegger