Issue
I am using Java and writing junit using spock framework in groovy, want to mock the HttpUrlConnection and set connection.getResponseCode() >> 200 as per different cases.
URL url = new URL(proxySettingDTO.getTestUrl());
HttpURLConnection connection = (HttpURLConnection) url.openConnection(proxy);
connection.setRequestMethod("GET");
connection.setUseCaches(false);
...
LOGGER.debug("Response code ::{} ",connection.getResponseCode()); //200 or 403
I have tried using
HttpURLConnection httpURLConnection = Mock()
URL url = new URL(proxySettingDTO.getTestUrl());
url.openConnection(_) >> httpURLConnection
But it is not working.
Solution
There are several things wrong in your question:
It consists of an incoherent set of incomplete code snippets instead of an MCVE, i.e. a complete, minimal example which everybody who wants to help you can compile and run without doing your job and making up example classes by themselves. That is your job.
In
url.openConnection(_) >> httpURLConnection
you are trying to stub a method result, but yourURL
object is not declared as a mock, stub or spy. I.e., your attempt is doomed to fail.Even if you would try to mock a
URL
, that JDK class is final, i.e. you cannot mock it, because mocks are subclasses.The class under test fetches the
HttpURLConnection
by callingurl.openConnection(proxy)
. Because of (3), the method is not mockable, so you should externalise connection creation into a helper classConnectionManager
and then inject a mock instance into the class under test in order to make it testable.
In general tests are a design tool, not just for covering your code with tests. If testing is difficult, it means that the component design is too tightly coupled. Let the tests help drive your design using TDD (test-driven development) or at least test-driven refactoring, even though the latter is a bit late and means rework. If you decouple your components more, e.g. by not creating the object instances your class depends on internally but enabling API users to inject them, e.g. via constructors or setters, testability is much better and you have fewer headaches.
How about this?
class UnderTest {
private Proxy proxy
private ProxySettingDTO proxySettingDTO
private ConnectionManager connectionManager
UnderTest(Proxy proxy, ProxySettingDTO proxySettingDTO, ConnectionManager connectionManager) {
this.proxy = proxy
this.proxySettingDTO = proxySettingDTO
this.connectionManager = connectionManager
}
int getConnectionResponseCode() {
URL url = new URL(proxySettingDTO.getTestUrl())
HttpURLConnection connection = (HttpURLConnection) connectionManager.openConnection(url, proxy)
connection.setRequestMethod("GET")
connection.setUseCaches(false)
connection.getResponseCode()
}
}
class ProxySettingDTO {
String getTestUrl() {
"https://scrum-master.de"
}
}
class ConnectionManager {
URLConnection openConnection(URL url, Proxy proxy) {
url.openConnection(proxy)
}
}
package de.scrum_master.stackoverflow.q71616286
import spock.lang.Specification
class HttpConnectionMockTest extends Specification {
def test() {
given: "a mock connection manager, returning a mock connection with a predefined response code"
ConnectionManager connectionManager = Mock() {
openConnection(_, _) >> Mock(HttpURLConnection) {
getResponseCode() >> 200
}
}
and: "an object under test using mock proxy, real DTO and mock connection manager"
def underTest = new UnderTest(Mock(Proxy), new ProxySettingDTO(), connectionManager)
expect: "method under test returns expected response"
underTest.getConnectionResponseCode() == 200
}
}
Try it in the Groovy web console.
Answered By - kriegaex
Answer Checked By - Candace Johnson (JavaFixing Volunteer)