【发布时间】:2010-12-08 10:22:43
【问题描述】:
我是正确的测试驱动设计或行为驱动设计的大力倡导者,我喜欢编写测试。但是,我一直把自己编码到一个角落,我需要在一个特定的测试用例中为单个类使用 3-5 个模拟。无论我以哪种方式开始,自上而下或自下而上,我最终的设计都需要来自最高抽象级别的至少三个协作者。
有人可以就如何避免这个陷阱给出好的建议吗?
这是一个典型的场景。我设计了一个从给定文本值生成 Midget 的 Widget。在我进入细节之前,它总是开始非常简单。我的 Widget 必须与几个难以测试的东西交互,比如文件系统、数据库和网络。
因此,我没有将所有这些都设计到我的小部件中,而是创建了一个 Bridget 合作者。 Bridget 处理了一半的复杂性,即数据库和网络,让我可以专注于另一半,即多媒体演示。所以,然后我制作了一个执行多媒体片段的小工具。整个事情需要在后台发生,所以现在我包括一个 Thridget 来实现它。当一切都说完了,我最终得到了一个 Widget,它将工作交给 Thridget,Thrridget 通过 Bridget 将其结果提供给 Gidget。
因为我在 CocoaTouch 中工作并试图避免模拟对象,所以我使用自分流模式,其中对协作者的抽象成为我的测试采用的协议。与 3 个以上的合作者一起,我的测试气球变得太复杂了。即使使用 OCMock 模拟对象之类的东西,也会给我留下一个我宁愿避免的复杂性顺序。我尝试将我的大脑围绕着一个菊花链的协作者(A 代表 B,B 代表 C 等等),但我无法想象。
编辑 下面举个例子,假设我们有一个对象必须从套接字读取/写入并显示返回的电影数据。
//Assume myRequest is a String param...
InputStream aIn = aSocket.getInputStram();
OutputStream aOut = aSocket.getOutputStram();
DataProcessor aProcessor = ...;
// This gets broken into a "Network" collaborator.
for(stuff in myRequest.charArray()) aOut.write(stuff);
Object Data = aIn.read(); // Simplified read
//This is our second collaborator
aProcessor.process(Data);
现在上面显然处理网络延迟,所以它必须是线程的。这引入了一个线程抽象来让我们摆脱线程单元测试的实践。我们现在有
AsynchronousWorker myworker = getWorker(); //here's our third collaborator
worker.doThisWork( new WorkRequest() {
//Assume myRequest is a String param...
DataProcessor aProcessor = ...;
// Use our "Network" collaborator.
NetworkHandler networkHandler = getNetworkHandler();
Object Data = networkHandler.retrieveData(); // Simplified read
//This is our multimedia collaborator
aProcessor.process(Data);
})
请原谅我在没有测试的情况下逆向工作,但我正要带我的女儿出去,我正在匆匆完成这个例子。这里的想法是,我正在从一个简单的界面后面协调几个协作者的协作,该界面将与 UI 按钮单击事件相关联。所以最外面的测试反映了一个 Sprint 任务,它说给定一个“播放电影”按钮,当它被点击时,电影就会播放。 编辑 让我们讨论一下。
【问题讨论】:
标签: unit-testing tdd mocking