Junit spring - @BeforeClass запускается до @ContextConfiguration

Я хочу выполнить вход вручную с помощью Spring Security в тесте junit, поэтому я использую @WebAppConfiguration и метод @BeforeClasssetUp() для установки springcontext, чтобы можно было использовать код springsecurity. Но поскольку @BeforeClass запускается перед аннотациями класса junit @WebAppConfiguration и @ContextConfiguration, значит, @Autowired для private WebApplicationContext wac имеет значение NULL в setUp() и вызывает сообщение об ошибке ниже. Затем я меняю @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 и т. д.

M. Deinum 11.10.2018 09:18
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
0
1
693
1

Ответы 1

@BeforeClass - это статический метод, поэтому переменная @Autowired дает значение null. 1) Один из подходов, который можно использовать, - это использование настраиваемого логического флага:

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

2) Другой подход (я не пробовал этого, но теоретический должен работать) использует аннотацию @BeforeAll.

Привет, Зоро, подход boolean_flag, похоже, не работает, я получаю сообщение об ошибке java.lang.NoSuchMethodError: javax.servlet.ServletContext.getContextPath()Ljava/lang/Stri‌​ng;, потому что мне нужно использовать @autowire bean WebApplicationContext в setup (), чтобы я мог установить контекст Spring, который используется в test01()

jacky 12.10.2018 04:20

Привет, зоро, подход @BeforeAll теперь также работает, я получаю сообщение об ошибке org.springframework.security.authentication.AuthenticationSe‌​rviceException at ericsson.core.security.LoginAuthenticationProvider.retrieveU‌​ser(LoginAuthenticat‌​ionProvider.java:87)‌, потому что setup() не запускается до test01(), поэтому ему не хватает контекста Spring для запуска кода springSecurity.

jacky 12.10.2018 04:33

Можете ли вы поделиться своим кодом о том, как вы реализовали подход с логическим флагом?

roronoa_zoro 12.10.2018 08:46

привет, вот фрагмент кода <br/> 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; }

jacky 12.10.2018 09:10

Вы не должны использовать @BeforeClass для инициализации флага используйте @Before

roronoa_zoro 12.10.2018 09:28

спасибо, как я уже упоминал в вопросе, я хочу найти способ использовать @BeforeClass в этом случае, чтобы метод setup() запускался только один раз во время тестирования класса. Но @Before в любом случае подойдет. еще раз спасибо. :)

jacky 12.10.2018 10:23

Другие вопросы по теме