5

所以我正在处理一些对手动数据库操作很重的遗留代码。我试图在这里保持一些表面上的质量,所以我会尽可能多地使用 TDD。

我正在处理的代码需要填充,比方说List<Foo>来自 DataReader,它返回正常运行的 Foo 所需的所有字段。但是,如果我想验证代码实际上是否为每个数据库行返回一个列表项,我正在编写如下所示的测试代码:

Expect.Call(reader.Read()).Return(true);
Expect.Call(reader["foo_id"]).Return((long) 1);
// ....
Expect.Call(reader.Read()).Return(true);
Expect.Call(reader["foo_id"]).Return((long) 2);
// ....
Expect.Call(reader.Read()).Return(false);

这也相当乏味且很容易损坏。

我应该如何处理这个问题,这样结果才不会是一团糟的脆弱测试?

顺便说一句,我目前正在为此使用 Rhino.Mocks,但如果结果足够令人信服,我可以更改它。只要替代品不是 TypeMock,因为他们的 EULA 对我上次检查的口味来说有点太吓人了。

编辑:我目前也仅限于 C# 2。

4

6 回答 6

1

为了使这不那么乏味,您将需要封装/重构 DataReader 和您在列表中保存的对象之间的映射。封装该逻辑的步骤很少。如果那是您想走的路,我可以为您发布代码。我只是不确定在 StackOverflow 上发布代码有多实用,但我可以试一试以保持简洁和重点。否则,您将被困在为读者重复索引访问器的每个期望的繁琐任务中。封装过程还将摆脱字符串并使这些字符串在您的测试中更易于重用。

此外,我目前不确定您希望使现有代码更具可测试性。因为这是在构建时没有考虑到测试的遗留代码。

于 2008-08-27T17:22:46.140 回答
1

我想发布一些代码,然后我想起了 JP Boodhoo 的 Nothin But .NET 课程。他有一个正在分享的示例项目,该项目是在他的一堂课中创建的。该项目托管在Google Code上,它是一个很好的资源。我相信它有一些不错的技巧供您使用,并为您提供有关如何重构映射的想法。整个项目是用 TDD 构建的。

于 2008-08-27T18:42:09.133 回答
0

您可以将 Foo 实例放在一个列表中,并将这些对象与您阅读的内容进行比较:

var arrFoos = new Foos[]{...}; // what you expect
var expectedFoos = new List<Foo>(arrFoos); // make a list from the hardcoded array of expected Foos
var readerResult = ReadEntireList(reader); // read everything from reader and put in List<Foo>
Expect.ContainSameFoos(expectedFoos, readerResult); // compare the two lists
于 2008-08-27T13:15:01.353 回答
0

科科斯,

那里有几件事不对劲。首先,这样做意味着我必须先构建 Foos,然后将它们的值提供给模拟阅读器,这对减少我正在编写的代码量没有任何作用。其次,如果值通过阅读器,则 Foos 将不是相同的Foos(引用相等)。它们可能是相等的,但即使这样也假设了我现在不敢触及的太多 Foo 类。

于 2008-08-27T17:00:00.517 回答
0

澄清一下,您希望能够测试您对 SQL Server 的调用返回了一些数据,或者如果您有一些数据可以将其映射回模型中?

如果您想测试您对 SQL 的调用返回了一些数据,请查看我在此处找到的答案

于 2008-08-27T17:42:35.673 回答
0

@Toran:我正在测试的是从数据库返回的数据到引用-取消引用域模型的编程映射。因此我想模拟出数据库连接。对于另一种测试,我会进行全面的集成测试。

@Dale:我猜你在那里做得很好,我担心可能是这种情况。如果您有任何文章或类似内容的指针,其中有人完成了肮脏的工作并将其分解为更容易消化的步骤,我将不胜感激。代码示例也不会受到伤害。我确实知道如何解决这个问题,但在我真正敢于这样做之前,我需要完成其他事情,如果测试需要进行乏味的模拟,那么这就是我要做的。

于 2008-08-27T18:01:49.917 回答