Этот вопрос связан с тестированием классов, которые смешиваются в неинтерфейсных чертах, это черты, содержащие некоторые функциональные возможности. При тестировании функциональность класса должна быть изолирована от функциональности, предоставляемой признаком смешения (который предположительно тестируется отдельно).
У меня есть простой класс Crawler
, который зависит от набора функций утилиты HttpConnection и HttpHelpers
. Теперь сосредоточьтесь на HttpHelpers.
В Java HttpHelpers, возможно, будет классом утилиты и передаст его singleton в Crawler в качестве зависимости, либо вручную, либо с некоторой картой IoC. Тестирование Crawler является простым, так как зависимость легко издевается.
В Scala кажется, что вспомогательный признак является более предпочтительным способом компоновки функциональности. В самом деле, его проще использовать (методы, автоматически импортируемые в пространство имен при расширении, могут использовать 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()
Вопрос
Этот подход делает работу, но необходимость иметь макетную черту поддержки для каждого вспомогательного признака немного утомительна. Однако я не вижу другого способа для этого работать.
- Это правильный подход?
- Если да, может ли его цель быть достигнута более эффективно (синтаксическая магия, плагин компилятора и т.д.)?
Любая обратная связь приветствуется. Спасибо!