“模拟”数据库与“真实”数据库行为之间的差异

时间:2009-04-27 20:41:46

标签: c# database linq count mocking

我们将C#和Linq2SQL与MS SQL Server数据库一起使用。 我们有一个mockdatacontext来进行一些单元测试。 在测试时,我们发现了两种不同的行为,具体取决于是使用“真实”还是“模拟”数据库。

场景1:真实数据库

数据库中有5条记录:

db = realDatabase
db.InsertOnSubmit(new record)

var count1 = db.getTable.Count()

db.SubmitChanges()

var count2 = db.getTable.Count()

count1 = 5 count2 = 6

场景2:模拟数据库

数据库中有5条记录:

db= mockDatabase

db.InsertOnSubmit(new record)

var count1 = db.getTable.Count()

db.SubmitChanges()

var count2 = db.getTable.Count()

count1 = 6 count2 = 6

*“模拟”数据库在调用SubmitChanges()之前已经知道新记录,因此它包含在计数中。对于测试,我们需要两个行为相同。

是否有其他人遇到此问题,您能否提出解决方案?

2 个答案:

答案 0 :(得分:7)

IMO,人们试图在测试中模拟是一个常见的错误。 模拟器不是模拟器。它不应该实现类似于原始的逻辑,它应该只返回硬编码结果。

如果模拟行为很复杂,您最终会测试模拟而不是商业代码。

我正在使用RhinoMocks,它看起来像这样:

// 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());

每次都会返回相同的列表。在许多情况下,这就足够了。您仍然可以在第二个getTable调用上返回其他数据:

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

它总是特定于单个测试,但这使它变得如此简单。

编辑:

我不得不承认我不熟悉Linq2Sql。在我的例子中被模拟的调用是Linq2Sql调用,这可能不容易被嘲笑。您可能需要将其置于简单的DAL界面之后。然后你嘲笑这个界面。

答案 1 :(得分:0)

我猜你的模拟数据库(在内存中)不是事务性的,而InsertOnSubmit方法实际上是在插入记录。