【发布时间】:2011-10-26 22:54:49
【问题描述】:
这个问题是关于处理混合非接口特征的类的测试,即包含一些功能的特征。测试时,应将类功能与 mix-in trait 提供的功能隔离开来(据说是单独测试的)。
我有一个简单的Crawler 类,它依赖于一个HttpConnection 和一个HttpHelpers 实用函数集合。现在让我们关注 HttpHelpers。
在 Java 中,HttpHelpers 可能是一个实用程序类,并将其单例作为依赖项传递给 Crawler,手动或使用某些 IoC 框架。测试爬虫很简单,因为依赖很容易模拟。
在 Scala 中,helper trait 似乎是组合功能的首选方式。确实,它更容易使用(扩展时自动导入命名空间的方法,可以使用withResponse ...代替httpHelper.withResponse ...等)。但它对测试有何影响?
这是我想出的解决方案,但不幸的是,它将一些样板文件提升到了测试端。
助手特质:
trait HttpHelpers {
val httpClient: HttpClient
protected def withResponse[A](resp: HttpResponse)(fun: HttpResponse => A): A = // ...
protected def makeGetRequest(url: String): HttpResponse = // ...
}
要测试的代码:
class Crawler(val httpClient: HttpClient) extends HttpHelpers {
// ...
}
测试:
// Mock support trait
// 1) Opens up protected trait methods to public (to be able to mock their invocation)
// 2) Forwards methods to the mock object (abstract yet)
trait MockHttpHelpers extends HttpHelpers {
val myMock: MockHttpHelpers
override def makeGetRequest(url: String): HttpResponse = myMock.makeGetRequest(url)
}
// Create our mock using the support trait
val helpersMock = Mockito.mock(classOf[MockHttpHelpers])
// Now we can do some mocking
val mockRequest = // ...
Mockito when (helpersMock.makeGetRequest(Matchers.anyString())) thenReturn mockRequest
// Override Crawler with the mocked helper functionality
class TestCrawler extends Crawler(httpClient) with MockHttpHelpers {
val myMock = helpersMock
}
// Now we can test
val crawler = new TestCrawler()
crawler.someMethodToTest()
问题
这种方法确实有效,但是需要为每个辅助 trait 提供一个模拟支持 trait 有点乏味。但是我看不出有任何其他方法可以做到这一点。
- 这是正确的方法吗?
- 如果是,能否更有效地实现其目标(语法魔术、编译器插件等)?
欢迎任何反馈。谢谢!
【问题讨论】:
标签: unit-testing scala traits