A Situation
I'm using wicket 9 for a web gui development. And now I'm trying to do some junit testing by mocking (mockito) methods that are not essential. One of those methods is
httpSession.getAttribute("loginName");
which gets called like this:
public class MyPanel {
...
SecureWebSession session = (SecureWebSession) getSession(); <--returns a SecuredWebSession
Label username = new Label("loginName", session.getLoginName()); <-- NullPointerException
...
}
Obviously, something is not right with how I'm mocking things. I expect it to return test, but all I get at all times is a NullPointerException.
My question is how can I bypass session.getLoginName() so, that the call would return a login name test?
How to mock httpSession while testing wicket application?
Details
I have a securedWebSession class
package com.my.app.application;
import com.my.app.service.signOnService;
import org.apache.wicket.authroles.authentication.AuthenticatedWebSession;
import org.apache.wicket.authroles.authorization.strategies.role.Roles;
import org.apache.wicket.injection.Injector;
import org.apache.wicket.request.Request;
import org.apache.wicket.spring.injection.annot.SpringBean;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.io.UnsupportedEncodingException;
public class SecureWebSession extends AuthenticatedWebSession {
@SpringBean(name = "authenticationManager")
private AuthenticationManager authenticationManager;
@SpringBean(name = "signOnService")
private SignOnService signOnService;
private final HttpSession httpSession;
private final Request request;
public SecureWebSession(Request request) {
super(request);
this.request = request;
//******************THIS I CANNOT BYPASS***************************************START
this.httpSession = ((HttpServletRequest) request.getContainerRequest())
.getSession(false);
//******************THIS I CANNOT BYPASS******ALLWAYS RETURNS NULL*************END
Injector.get().inject(this);
}
@Override
public boolean authenticate(String username, String password) {
return true;
}
private boolean hasSignedIn(Authentication authentication) {
return authentication.isAuthenticated();
}
@Override
public Roles getRoles() {
Roles roles = new Roles();
roles.add("SUPER_ADMIN");
return roles;
}
public String getLoginName() {
********RETURNS NULL.getAttribute("loginName")******
return (String) httpSession.getAttribute("loginName");
}
}
I have a test setup as following
@ExtendWith(SpringExtension.class)
@SpringBootTest(classes = {
MyWicketApplication.class
})
public class ApplicationTest {
private WicketTester tester;
private final WebApplication webApplication;
@Autowired
public SecuredWicketGuiApplicationTest(WebApplication application) {
this.webApplication = application;
}
@BeforeEach
public void setUp() {
//**** ** * WORKS ** ** ** **
// when authenticated is given
Authentication authentication = Mockito.mock(Authentication.class);
SecurityContext securityContext = Mockito.mock(SecurityContext.class);
Mockito.when(securityContext.getAuthentication()).thenReturn(authentication);
Mockito.when(authentication.isAuthenticated()).thenReturn(true);
SecurityContextHolder.setContext(securityContext);
//** ** ** ** ** ** ** ** ** *
// and secured session is provided
SecureWebSession secureWebSession = Mockito.mock(SecureWebSession.class);
//**** ** * WORKS ** ** ** **
// and a superuser role is given
Roles roles = new Roles();
roles.add("SUPER_ADMIN");
Mockito.when(secureWebSession.getRoles()).thenReturn(roles);
//** ** ** ** ** ** ** ** **
// and session has loginName attribute
HttpSession session = Mockito.mock(HttpSession.class);
Mockito.when(session.getAttribute("loginName")).thenReturn("test");
HttpServletRequest request = Mockito.mock(HttpServletRequest.class);
Mockito.when(request.getSession()).thenReturn(session);
tester = new WicketTester(webApplication);
MockHttpSession mockHttpSession = new MockHttpSession(null);
mockHttpSession.setAttribute("loginName", "test");
// and a requested initiated for a given session
MockHttpServletRequest mockedRequest = new MockHttpServletRequest(
tester.getApplication(), mockHttpSession, null) {
@Override
public HttpSession getSession(boolean createNew) {
return mockHttpSession;
}
@Override
public HttpSession getSession() {
return mockHttpSession;
}
};
// and a session object is created with a loginName attribute test
tester.getRequest().getSession()
.setAttribute("loginName", "test");
tester.setRequest(mockedRequest);
}
@Test
public void HomePage_Renders_Successfully() {
// then start and render the homePage page
tester.startPage(HomePage.class);
// assert rendered HomePage component
tester.assertRenderedPage(HomePage.class);
}
}
when I try to execute this test I get stuck on
public class MyPanel {
...
SecureWebSession session = (SecureWebSession) getSession(); <--returns a SecuredWebSession
Label username = new Label("loginName", session.getLoginName()); <-- NullPointerException
...
}
Where method getLoginName is defined in securedWebSession
public String getLoginName() {
********RETURNS NULL.getAttribute("loginName")******
return (String) httpSession.getAttribute("loginName");
}
CodePudding user response:
You create several objects via their constructors but they (most of them) are not used later. WicketTester uses the passed Application to find the others, i.e. it uses application#newSession() to create the Wicket Session, and application#newRequest() to create the Wicket Request. If you want to use mock versions of those then you need to create a custom MyTestWebApplication (that extends from MyWicketApplication), override these methods and set it up as a Spring bean.
WicketTester uses a new/fresh instance of MockHttpServletRequest for each request. You can get a reference to it via tester.getRequest()
and call its #setAttibute()method before actually making the HTTP call (e.g. via
clickLink(),
executeAjaxEvent()or
startPage()`).
So you could just use tester.getHttpSession().setAttribute(..., ...)
before making the http call.