tags:

views:

102

answers:

7

Let's say I'm writing an application and I need to be able to do something like this:

String url = "https://someurl/";
GetMethod method = new GetMethod(URLEncoder.encode(url));
String content = method.getResponseBodyAsString();

Is there a way to provide a mock server that would let me handle the https request? What I'm looking for is a way to write unit tests, but I need to be able to mock the part that actually goes out to https://someurl so I can get a known response back.

+1  A: 

Take a look at JWebUnit http://jwebunit.sourceforge.net/

Here is an example of a test...Its really quite intuitive.

public class ExampleWebTestCase extends WebTestCase {
    public void setUp() {
        super.setUp();
        setBaseUrl("http://localhost:8080/test");
    }

    public void test1() {
        beginAt("/home");
        clickLink("login");
        assertTitleEquals("Login");
        setTextField("username", "test");
        setTextField("password", "test123");
        submit();
        assertTitleEquals("Welcome, test!");
    }
}
Codemwnci
yes, I'm familiar with JWebUnit, but here I need to be able to mock the actual url being served up. JWebUnit works when the web site/service you are calling is actually running.
dcp
+1  A: 

You could always launch a thttpd server as part of your unit test to serve the requests locally. Though, ideally, you have a well tested GetMethod, and then you can just mock it, and not have to actually have a remote server around for ALL of your tests.

Resources

zigdon
+1  A: 

You can wrap that code in some class and have WebClient.getUrl() and then mock (e.g. jmock) that method to return stored files - say

expectation {
   oneOf("https://someurl/"), will(returnValue(someHTML));
}
+2  A: 

If you are writing a unit test, you dont want any external dependencies. from the api,

GetMethod 

extends

HttpMethod

so you can easily mock it with your favorite mocking library. Your

method.getResponseBodyAsString()

call can be mocked to return any data you want.

hvgotcodes
But the GetMethod is being created in the code itself, not in my unit test, so I can't mock it.
dcp
I dont understand, you dont control the code you are testing?
hvgotcodes
I control the code, but the GetMethod object is being created inside of the method that I'm testing, so I can't pass in a mock object. The way a mock works is that you set it up beforehand and pass it to whatever method you're testing, but in this case, The GetMethod object is being created inside the method itself, so I can't pass it in. If it's not clear, please let me know.
dcp
@dcp, ah gotya now. Well, the obvious answer is refactor to you inject or just set the HttpMethod you want....that might be better than using some external dependency to go to the web, which is going to fail unexpectedly. Better to have consistency in the tests...
hvgotcodes
Not sure what you mean by "refector to you inject or just set the HttpMethod you want", can you elaborate? The other idea I had was to just create a mock library for the Http Client, then I could just do what I wanted (i.e. I'd create my own mock implementations for GetMethod, etc.).
dcp
+1  A: 

Here's a similar question

It deals with debugging JSP pages, but it works the same with static pages

Bryce Fischer
+1  A: 

To what extend are you interested in mocking this "Get" call, because if you are looking for a general purpose mocking framework for Java which integrates well with JUnit and allows to setup expectations which are automatically asserted when incorporated into a JUnit suite, then you really ought to take a look at jMock.

Now without more code, it's hard to determine whether this is actually what you are looking for, but a (somewhat useless) example, of something similar to the example code you wrote, would go something like this:

class GetMethodTest {
@Rule public JUnitRuleMockery context = new JunitRuleMockery();

@Test
public void testGetMethod() throws Exception {
    // Setup mocked object with expectations
    final GetMethod method = context.mock(GetMethod.class);
    context.checking(new Expectations() {{
        oneOf (method).getResponseBodyAsString();
        will(returnValue("Response text goes here"));
    }});

    // Now do the checking against mocked object
    String content = method.getResponseBodyAsString();
}
}
micdah
Won't really work in my case, see my comments to hvgotcodes.
dcp
Hmm then I might consider using a Java extension framework like Object Teams, which is capable of re-routing specific method calls to your own defined methods, thus you can tap into the precise point of the control flow you need to alter, to inject either your own code or your mocked object. It doesn't matter whether it's a public or private method, ObjecTeams acts as a superset to Java, so you can do things Java normally wouldn't be able to do.
micdah
+1  A: 

You essentially have two options:

1. Abstract the call to the framework and test this.

E.g. refactor the code to allow you to inject a mock implementation at some point. There are many ways to do this. e.g. create a getUrlAsString() and mock that. (also suggested above). Or create a url getter factory that returns a GetMethod object. The factory then can be mocked.

2. Start up a app server as part of the test and then run your method against it. (This will be more of an integration test)

This can be achieved in an number of ways. This can be external to the test e.g. the maven jetty plugin. or the test can programmatically start up the server. see: http://docs.codehaus.org/display/JETTY/Embedding+Jetty

Running it over https will complicate this but it will still be possible with self signed certs. But I'd ask yourself - what exactly you want to test? I doubt you actually need to test https functionality, its a proven technology.

Personally I'd go for option 1 - you are attempting to test functionality of an external library. That is usually unnecessary. Also it's good practice to abstract out your dependencies to external libraries.

Hope this helps.

Pablojim