Discrepancies between “Mock” Database and “Real” database behaviours

Discrepancies between “Mock” Database and “Real” database behaviours

风苍溪 发布于 2021-11-27 字数 1176 浏览 865 回复 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?

如果你对这篇文章有疑问,欢迎到本站 社区 发帖提问或使用手Q扫描下方二维码加群参与讨论,获取更多帮助。

扫码加入群聊

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

御弟哥哥 2022-06-07 2 楼

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

装纯掩盖桑 2022-06-07 1 楼

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 your 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.