wicket 9: 单元测试 + mockito + httpSession

wicket 9: unit testing + mockito + httpSession

情况

我正在使用 wicket 9 进行 web gui 开发。现在我正在尝试通过模拟(mockito)非必需的方法来进行一些 junit 测试。其中一种方法是

httpSession.getAttribute("loginName");

这样调用的:

public class MyPanel {
         ...

     SecureWebSession session = (SecureWebSession) getSession(); <--returns a SecuredWebSession
     Label username = new Label("loginName", session.getLoginName()); <-- NullPointerException
        ...
}

显然,我嘲笑事物的方式有些不对。我希望它进行 return 测试,但我始终得到 NullPointerException。

我的问题是如何绕过 session.getLoginName() 以便调用 return 登录名测试?

如何在测试 wicket 应用程序时模拟 httpSession?

详情

我有一个 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");
    }
}

我有一个测试设置如下

@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);
  }
}

当我尝试执行此测试时,我卡住了

public class MyPanel {
     ...

 SecureWebSession session = (SecureWebSession) getSession(); <--returns a SecuredWebSession
 Label username = new Label("loginName", session.getLoginName()); <-- NullPointerException
    ...
}

在 securedWebSession 中定义方法 getLoginName 的地方

public String getLoginName() {
 ********RETURNS NULL.getAttribute("loginName")******
    return (String) httpSession.getAttribute("loginName");
}

您通过它们的构造函数创建了几个对象,但它们(其中大部分)以后不会使用。 WicketTester 使用传递的应用程序来查找其他应用程序,即它使用 application#newSession() 创建 Wicket 会话,并使用 application#newRequest() 创建 Wicket 请求。如果你想使用这些的模拟版本,那么你需要创建一个自定义的 MyTestWebApplication(从 MyWicketApplication 扩展),覆盖这些方法并将其设置为 Spring bean。

WicketTester 为每个请求使用一个 new/fresh MockHttpServletRequest 实例。您可以通过 tester.getRequest() 获取对它的引用并调用其 #setAttibute()method before actually making the HTTP call (e.g. viaclickLink(), executeAjaxEvent()orstartPage()`).

因此您可以在进行 http 调用之前使用 tester.getHttpSession().setAttribute(..., ...)