Вот модульный тест, который отлично работает.
@Subject([WeatherServiceImpl.class,URLConnection.class])
class WeatherServiceImplSpec extends Specification{
def "First spock test I ever wrote"(){
given: "some mock objects"
//1. define mock HttpURLConnection object
def mockConnObj=Mock(HttpURLConnection.class)
//2. defn of another mock
def mockURLAdaptor=Mock(URLAdapter)
when: "define some calls"
def test=new WeatherServiceImpl(mockURLAdaptor)
test.run("Raleigh")
then: "make some assertions"
1*mockURLAdaptor.openConnection(_)>>mockConnObj
1*mockConnObj.getResponseCode()
}//end def test
}
Чего я не понимаю, так это того, что если я сделаю это в «данном» блоке:
def mockURLAdaptor = Mock(URLAdapter) >> {
openConnection(_) >> mockConnObj
}
тогда заглушка метода на самом деле не возвращает фиктивный объект соединения, как предполагалось. Для меня это более естественный поток выражений. Однако то же самое в блоке «тогда» работает так, как задумано. Не знаю, что здесь происходит. Не могу найти соответствующее обсуждение в сети. Я также могу опубликовать это на stackoverflow.
Вот тестируемый класс:
package com.icidigital.services.impl
import com.icidigital.Helpers.URLAdapter
import com.icidigital.services.IWeatherService
public class WeatherServiceImpl implements IWeatherService {
private URLAdapter urlAdapter;
private URLConnection urlConn;
public WeatherServiceImpl(URLAdapter urlAdapter){
//injecting this dependency, so I can unit test
//by injecting a mock URLAdapter instance. In
//normal operation, urlAdaptee would be an instance
//of URLWrapper, which simply wraps around the
// URL class, which is a final class and cannot
// be mocked normally.
this.urlAdapter=urlAdapter;
}
public String run(String city){
...
..
urlConn=urlAdapter.openConnection(city);
//(throws a null pointer exception while spock-ing)
urlConn.setRequestMethod("GET");
}
}
А вот URL-адаптер, который предоставляет метод: openConnection. В работающем коде есть класс URLWrapper, который просто обертывает класс java.net.URL. Мне нужно было сделать это, чтобы обойти тот факт, что я не мог напрямую издеваться над классом java.net.URL, поскольку это окончательный класс.
interface URLAdapter {
public HttpURLConnection openConnection(String cityName);
}