下面的测试类验证一个简单的 HttpService 从给定的 URL 获取内容。显示的两种实现都使测试通过,尽管其中一种显然是错误的,因为它使用不正确的参数构造 URL。
为了避免这种情况并正确指定我想要的行为,我想验证在测试用例的使用 block 中,我构造了一个(并且只有一个)URL 类的实例,并且 构造函数的 url
参数是正确的。 A Groovy enhancement好像它会让我添加声明
mockURLContext.demand.URL { assertEquals "http://www.foo.com", url }
但是如果没有 Groovy 增强我能做什么呢?
更新:将标题中的“mock”替换为“stub”,因为我只对检查状态感兴趣,不一定是交互的细节。 Groovy 有一个我没有使用过的 StubFor 机制,所以我将保留我的代码原样,但我认为您可以在整个过程中将 MockFor 替换为 StubFor。
import grails.test.*
import groovy.mock.interceptor.MockFor
class HttpServiceTests extends GrailsUnitTestCase {
void testGetsContentForURL() {
def content = [text : "<html><body>Hello, world</body></html>"]
def mockURLContext = new MockFor(URL.class)
mockURLContext.demand.getContent { content }
mockURLContext.use {
def httpService = new HttpService()
assertEquals content.text, httpService.getContentFor("http://www.foo.com")
}
}
}
// This is the intended implementation.
class HttpService {
def getContentFor(url) {
new URL(url).content.text
}
}
// This intentionally wrong implementation also passes the test!
class HttpService {
def getContentFor(url) {
new URL("http://www.wrongurl.com").content.text
}
}
最佳答案
模拟 URL 会给您带来什么?这使得测试难以编写。您将无法对模拟对象为您提供的有关 URL 类 API 设计的反馈使用react,因为它不在您的控制之下。如果您不精确地伪造 URL 的行为以及它所公开的有关 HTTP 协议(protocol)的内容,测试将不可靠。
您想测试您的“HttpService”对象是否确实从给定的 URL 正确加载数据,正确处理不同的内容类型编码,适本地处理不同类别的 HTTP 状态代码,等等。当我需要测试这种对象时——一个仅仅包装了一些底层技术基础设施的对象——我编写了一个真正的集成测试来验证该对象是否确实正确地使用了底层技术。
对于 HTTP,我编写了一个创建 HTTP 服务器的测试,将一个 servlet 插入将返回一些固定数据的服务器,将 servlet 的 URL 传递给对象以使其加载数据,检查加载结果是否为与用于初始化 servlet 的固定数据相同,并在 fixture 拆卸中停止服务器。我使用 Jetty 或与 JDK 6 捆绑在一起的简单 HTTP 服务器。
我只会使用模拟对象来测试与我已经集成测试的那个对象的接口(interface)对话的对象的行为。
关于unit-testing - Groovy:验证 stub URL 的构造,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/992656/