3

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

场景一:真实数据库

数据库中有5条记录:

db = realDatabase
db.InsertOnSubmit(new record)

var count1 = db.getTable.Count()

db.SubmitChanges()

var count2 = db.getTable.Count()

计数 1 = 5 计数 2 = 6

场景 2:模拟数据库

数据库中有5条记录:

db= mockDatabase

db.InsertOnSubmit(new record)

var count1 = db.getTable.Count()

db.SubmitChanges()

var count2 = db.getTable.Count()

计数 1 = 6 计数 2 = 6

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

有没有其他人遇到过这个问题,你能提出解决方案吗?

4

2 回答 2

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 接口后面。然后你模拟这个界面。

于 2009-04-29T22:20:14.340 回答
0

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

于 2009-04-29T18:39:20.237 回答