【问题标题】:junit spring - @BeforeClass run before @ContextConfigurationjunit spring - @BeforeClass 在 @ContextConfiguration 之前运行
【发布时间】:2018-10-11 06:36:15
【问题描述】:

我想在junit测试中使用spring security手动登录,所以我使用@WebAppConfiguration@BeforeClasssetUp()方法设置springcontext,以便springsecurity代码可以使用。
但是由于@BeforeClass在junit类注解@WebAppConfiguration@ContextConfiguration之前运行,所以private WebApplicationContext wac@AutowiredsetUp()中为空,并导致下面的错误消息。
然后我把@BeforeClass改成@Before,问题就解决了。
有什么办法还能用@BeforeClass也能解决问题吗?

测试类

import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.ServletException;

import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.mock.web.MockServletContext;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.web.context.ContextLoaderListener;
import org.springframework.web.context.WebApplicationContext;


@ContextConfiguration(locations = {
    "classpath:/springTest/applicationContext_test.xml",
    "classpath:/applicationContext-security.xml",
    "classpath:/spring/applicationContext-repository.xml"
    })
@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
public class xxxTest {

  @Autowired
  private xxx target;

  @Autowired
  private LoginAuthenticationProvider loginAuthenticationProvider;

  @Autowired
  private WebApplicationContext wac;

  //set the context
  @BeforeClass
  public void setUp() throws ServletException {
    ServletContextListener listener = new ContextLoaderListener(wac);
    ServletContextEvent event = new ServletContextEvent(new MockServletContext(""));
    listener.contextInitialized(event);
  }

  //mock login(manually login)
  @Test
  public void test01() {
    UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("user", "password");
    Authentication authentication = loginAuthenticationProvider.authenticate(token);
    SecurityContextHolder.getContext().setAuthentication(authentication);

    //other test code......
  }


}

错误信息

2018-10-10 19:18:48,006 [main] INFO  [org.springframework.test.context.web.WebTestContextBootstrapper] - Using TestExecutionListeners: [org.springframework.test.context.web.ServletTestExecutionListener@769e7ee8, org.springframework.test.context.support.DirtiesContextBeforeModesTestExecutionListener@5276e6b0, org.springframework.test.context.support.DependencyInjectionTestExecutionListener@71b1176b, org.springframework.test.context.support.DirtiesContextTestExecutionListener@6193932a]
2018-10-10 19:18:48,038 [main] INFO  [org.springframework.mock.web.MockServletContext] - Initializing Spring root WebApplicationContext
2018-10-10 19:18:48,038 [main] INFO  [org.springframework.web.context.ContextLoader] - Root WebApplicationContext: initialization started
2018-10-10 19:18:48,166 [main] INFO  [org.springframework.web.context.support.XmlWebApplicationContext] - Refreshing Root WebApplicationContext: startup date [Wed Oct 10 19:18:48 CST 2018]; root of context hierarchy
2018-10-10 19:18:48,216 [main] INFO  [org.springframework.beans.factory.xml.XmlBeanDefinitionReader] - Loading XML bean definitions from ServletContext resource [/WEB-INF/applicationContext.xml]
2018-10-10 19:18:48,218 [main] ERROR [org.springframework.web.context.ContextLoader] - Context initialization failed
org.springframework.beans.factory.BeanDefinitionStoreException: IOException parsing XML document from ServletContext resource [/WEB-INF/applicationContext.xml]; nested exception is java.io.FileNotFoundException: Could not open ServletContext resource [/WEB-INF/applicationContext.xml]
    at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:344)
    at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:304)
    at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:181)
    at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:217)
    at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:188)
    at org.springframework.web.context.support.XmlWebApplicationContext.loadBeanDefinitions(XmlWebApplicationContext.java:125)
    at org.springframework.web.context.support.XmlWebApplicationContext.loadBeanDefinitions(XmlWebApplicationContext.java:94)
    at org.springframework.context.support.AbstractRefreshableApplicationContext.refreshBeanFactory(AbstractRefreshableApplicationContext.java:129)
    at org.springframework.context.support.AbstractApplicationContext.obtainFreshBeanFactory(AbstractApplicationContext.java:614)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:515)
    at org.springframework.web.context.ContextLoader.configureAndRefreshWebApplicationContext(ContextLoader.java:443)
    at org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:325)
    at org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:107)
    at ericsson.rtm.service.chache.xxxTest.setUp(xxxTest.java:54)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
    at mockit.integration.junit4.internal.JUnit4TestRunnerDecorator.invokeExplosively(JUnit4TestRunnerDecorator.java:33)
    at mockit.integration.junit4.internal.MockFrameworkMethod.invokeExplosively(MockFrameworkMethod.java:44)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java)
    at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:24)
    at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
    at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:191)
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:86)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:675)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)
**Caused by: java.io.FileNotFoundException: Could not open ServletContext resource [/WEB-INF/applicationContext.xml]**
    at org.springframework.web.context.support.ServletContextResource.getInputStream(ServletContextResource.java:141)
    at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:330)
    ... 34 more

【问题讨论】:

  • 不,你到底为什么要在测试中创建ContextLoaderListener?!看起来你在做错事。添加对spring-security-test 的依赖并使用@WithUser 等注解。

标签: java spring junit spring-security


【解决方案1】:

@BeforeClass 是一个静态方法,这就是 @Autowired 变量给出 null 的原因。 1)可以使用的一种方法是使用自定义布尔标志:

private static boolean isInitialized = false;
.....
public void setUp() {
    if (isInitialized) {
        return;
    }
    // do the setup
    isInitialized = true;
}

2) 另一种方法(我没有尝试过,但理论上应该可行)是使用 @BeforeAll 注释。

【讨论】:

  • 嗨 zoro,boolean_flag 方法似乎不起作用,我收到错误 java.lang.NoSuchMethodError: javax.servlet.ServletContext.getContextPath()Ljava/lang/String; 因为我必须在 setup() 中使用 @autowire bean WebApplicationContext 以便我可以设置使用的弹簧上下文test01()
  • 嗨 zoro,@BeforeAll 方法现在也可以正常工作,我收到错误 org.springframework.security.authentication.AuthenticationServiceException at ericsson.core.security.LoginAuthenticationProvider.retrieveUser(LoginAuthenticationProvider.java:87),因为 setup() 没有在 test01() 之前运行,因此它缺少弹簧上下文运行 springSecurity 代码。
  • 你能分享你如何实现布尔标志方法的代码吗?
  • 嗨,这里是代码 sn-p
    private static boolean isInitialized = false; @BeforeClass public static void setUp() throws ServletException { if (isInitialized) { return; } ServletContextListener listener = new ContextLoaderListener(wac); ServletContextEvent event = new ServletContextEvent(new MockServletContext("")); listener.contextInitialized(event); isInitialized = true; }
  • 您不应该使用@BeforeClass 进行标志初始化使用@Before
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-08-31
  • 2018-09-02
相关资源
最近更新 更多