views:

3335

answers:

2

I am new to jmock and trying to mock an HttpSession. I am getting:

java.lang.AssertionError: unexpected invocation: httpServletRequest.getSession() no expectations specified: did you... - forget to start an expectation with a cardinality clause? - call a mocked method to specify the parameter of an expectation?

the test method:

@Test

public void testDoAuthorization(){

 final HttpServletRequest request = context.mock(HttpServletRequest.class);
 final HttpSession session = request.getSession();

 context.checking(new Expectations(){{
       one(request).getSession(true); will(returnValue(session));
   }});

 assertTrue(dwnLoadCel.doAuthorization(session));
}

I have done a bit of searching and it isn't clear to me still how this is done. Feels like I am missing some small piece. Anyone with experience in this can just point me in the right direction. thanks

+1  A: 

I think you need to tell the JMock context how many times you expect the method to be called before you actually go ahead and call it.

final HttpServletRequest request = context.mock(HttpServletRequest.class);

context.checking(new Expectations(){{
  one(request).getSession(true); will(returnValue(session));
}});

final HttpSession session = request.getSession();

I'm not super familiar with JMock but do you actually care in your dwnLoadCel unit test how many times certain methods in the mocked object are called? Or are you just trying to test your class that depends on a HttpSession without an actual Session? If it's the latter than I think that JMock is overkill for you.

You might want to look into either creating a class that implements the HttpSession interface yourself for the purposes of unit testing only (a stub), and running your tests off of that, or you should take a look at dwnLoadCel and determine if it really needs to have a reference to the HttpSession, or if it just needs some properties within the HttpSession. Refactor dwnLoadCel to only depend on what it actually needs (a Map or a certain parameter value within the Session object) - this will make your unit test easier (the dependency on the servlet container goes bye-bye).

I think that you have some level of dependency injection in your class being tested already, but you might be dependent on too broad of an object. The Google Test Blog has had a lot of excellent articles on DI lately that you might find useful (I sure have).

matt b
good answer. After reviewing the problem it seems reasonable to take a look at the class that dwnLoadCel uses for doAuthorization. Maybe refactoring that is an option.
SWD
For the record, there's the 'allowing()' clause in jMock which effectively stubs a call. It allows the call to be made as many times as you like. We usually 'allow' queries which do not change the state of the collaborator
Steve Freeman
+1  A: 

You don't need to mock the request object. Since the method you're testing (dwnLoadCel.doAuthorization()) only depends on an HttpSession object, that is what you should mock. So your code would look like this:

public void testDoAuthorization(){
    final HttpSession session = context.mock(HttpSession.class);

    context.checking(new Expectations(){{
        // ???
    }});

    assertTrue(dwnLoadCel.doAuthorization(session));

}

The question becomes: what do you expect the SUT to actually do with the session object? You need to express in your expectations the calls to session and their corresponding return values that are supposed to result in doAuthorization returning true.

Kris Pruden
this helped me in the right direction. I needed to just use the httpssession and upgrade my version of hamcrest.
SWD