I'm trying to do E2E testing (or as close as I can get to E2E) for a Jetty application. I have a neat set-up involving testcontainers and minimal mocking, and everything works in principle, except that I am now having to mock the HTTP workflow that would be handled by Jetty, because I run my tests with JUnit, and all of this because I need to test methods that require authentication -- and yes, I could mock the authentication layer, but I'd rather not for reasons.
Anyway, this is what I'm ending up doing:
String someSegueAnonymousUserId = "9284723987anonymous83924923";
HttpSession httpSession = createNiceMock(HttpSession.class);
// At first, an anonymous user is "created"
expect(httpSession.getAttribute(Constants.ANONYMOUS_USER)).andReturn(null).atLeastOnce();
expect(httpSession.getId()).andReturn(someSegueAnonymousUserId).atLeastOnce();
replay(httpSession);
Capture<Cookie> capturedCookie = Capture.newInstance(); // new Capture<Cookie>(); seems deprecated
// This is the HTTP request for the login step
HttpServletRequest loginRequest = createNiceMock(HttpServletRequest.class);
expect(loginRequest.getSession()).andReturn(httpSession).atLeastOnce();
replay(loginRequest);
// The login process takes the auth cookie and sticks it into the HTTP response
// I capture the cookie because I'm going to need it for subsequent requests, to prove that I'm logged in
HttpServletResponse loginResponse = createNiceMock(HttpServletResponse.class);
loginResponse.addCookie(and(capture(capturedCookie), isA(Cookie.class)));
expectLastCall().atLeastOnce();
replay(loginResponse);
// This is the request for the endpoint I'm going to test
HttpServletRequest createBookingRequest = createNiceMock(HttpServletRequest.class);
// I expect that the endpoint method will check authentication by grabbing the cookies from the request
// Test case fails here: I can't find a way to cast the Object[] returned by the toArray() method to a Cookie[] which is what getCookies() is expected to return.
expect(createBookingRequest.getCookies()).andReturn((Cookie[]) Collections.singletonList(capturedCookie).toArray()).atLeastOnce();
replay(createBookingRequest);
// OK, so, this logs me in, and it works just fine, the cookie is created, and it is valid as far as I can tell
RegisteredUserDTO testUsers = userAccountManager.authenticateWithCredentials(loginRequest, loginResponse, AuthenticationProvider.SEGUE.toString(), "[email protected]", "testpassword", false);
// I don't even get here at all because of that failure above
Response createBookingResponse = eventsFacade.createBookingForMe(createBookingRequest, "someEventId", null);
Now, either there is a way of fixing this, or I'm doing it terribly wrong and I should be doing things very differently. However, I can't find much guidance on the Internet, so my suspicion that I'm doing something that I'm not supposed to do.
Any pointers to how I should do things differently?
As you indicated in your code comments, the problem seems to be related to the following line:
which is originating a
ClassCastException:As I indicated in my comment to your question too, please, try using the
CaptureclassgetValue()method to obtain a reference to the captured value, and use that value to provide the necessary return information to thecreateBookingRequest.getCookies()expectation, something like this:Note the use of the
getValue()method.Be aware that in order to use the proposed solution is very important that you invoke the
logingResponse.addCookie(...)method before performing the actualcapturedCookie.getValue()invocation.I mean, suppose the following code fragment in which I included the proposed change:
If you run the test, it will fail with the following error message:
It makes perfect sense because the captured value will only be available when the "watched" method, the one we want to capture the arguments for,
loginResponse.addCookie(...)in this case, is invoked.To solve the problem, perhaps you could try reordering your code and only call the
capturedCookie.getValue()when the authentication flow is finished, probably in some place in youruserAccountManager.authenticateWithCredentialsmethod invocation. For example:With this new setup, be sure that within your
userAccountManagerauthenticateWithCredentialsmethod you invokeloginResponse.addCookie: