[JAVA] Lösen Sie Nullzeiger für verschiedene Sitzungen während des MVC-Tests von Spring Boot auf.

In der Spring Boot-Anwendung entwickeln wir Als ich mvc mit MockMvc getestet habe Da beim Abrufen der Sitzungsvariablen eine Ausnahme mit einem Nullzeiger ausgelöst wird, wird die Lösung in diesem Fall zusammengefasst.

Ich denke, es kann Missverständnisse und andere Methoden geben. Wir werden das Problem beheben, sobald wir eine neue oder eine bessere Methode finden. Wir würden uns freuen, wenn Sie auf Fehler in der Beschreibung oder Anerkennung hinweisen könnten. Vielen Dank für Ihre wertvolle Zeit zu dieser Zeit.

Schreibe nicht

· Testaufbau (Satz von Gradle und MVN)

.with(user(mockuser))Authentifizieren und ausführen bei.



### Umgebung
spring boot 1.3.x
java 1.8


## Hintergrund

 Beim MVC-Test die Controller-Methode
 Nach der Ausführung wird es zu einem Nullzeiger, wenn auf eine Instanz vom Sitzungstyp verwiesen wird.
 Ich war in Schwierigkeiten, weil ich nicht testen konnte.
 Wenn Sie darüber nachdenken, melden Sie sich nicht an und bedienen es nicht.
 Es gibt keine Sitzungsinstanz, die sich anmelden und arbeiten soll
 Offensichtlich war ich mir nicht sicher, was ich tun sollte.
 Aufgrund verschiedener Untersuchungen gelang es mir, fortzufahren, und ich schrieb es als Memo
 Die Lösung hat lange gedauert, daher hoffe ich, dass es für diejenigen hilfreich ist, die Probleme mit demselben Teil haben.


## Worauf bezieht sich der MVC-Test in diesem Artikel?
 Zunächst werde ich Ihnen zeigen, was der MVC-Test in diesem Fall ist.
 Geben Sie die HTTP-Methode an, indem Sie die URL wie unten gezeigt angeben
 Der Rückgabewert und andere Dinge, die verschiedene Zustände testen.

```java
        @Test
        public void getTest() throws Exception {
    
            ResultActions resultActions =
                    mockMvc.perform(MockMvcRequestBuilders.get("/data/showList")                    
                            .with(user(mockAdminUser)))
                            .andExpect(MockMvcResultMatchers.status().is2xxSuccessful());
        }

Drei Hauptprobleme

Das Problem war hauptsächlich mit 3 Nullzeigern.

-① Es wird null, da die in request.getSession.getAttribute verwendete Sitzung nicht festgelegt ist. --② Die Instanz ist in dem Teil, in dem @Autowired HttpServletRequest instanziiert wird, null. --③ Die in Session Bean definierte Variable ist null, wenn sie in @Autowired verwendet wird.

Die Lösung

Über ①

Dieses Problem tritt beim Zugriff auf die URL auf, die Sie testen Ein Nullzeiger trat auf, als die folgende Beschreibung in der Logik vorgenommen wurde.


    @Autowired
    HttpServletRequest request;
    
    public void f() {
        //Anfrage ist null.Nullzeiger Ausnahme während getSession
        Object o = request.getSession.getAttribute("abc");
    }

Dieses Problem kann gelöst werden, indem beim Testen Folgendes eingestellt wird Sie können jetzt HttpServletRequest injizieren.


    HttpServletRequest request;
    
    request = new MockHttpServletRequest();
    RequestContextHolder.setRequestAttributes(new ServletWebRequest(request));

Durch Beschreiben der obigen Informationen zum Zeitpunkt der Einrichtung, z. B. @Before zum Zeitpunkt der Testausführung, kann die Instanz im Aufruf der zu testenden Methode verwendet werden. Die Offshore-Mitglieder, die demselben Projekt zugeordnet waren, verwendeten es in anderen Tests (nicht in Mvc-Tests), daher habe ich dies als Referenz verwendet.

Ich kann nicht gut Englisch, aber weil es wie folgt ist Semantisch "Anforderungsattribute an die aktuelle Bedrohung binden" Heisst das

    /**
    	 * Bind the given RequestAttributes to the current thread,
    	 * <i>not</i> exposing it as inheritable for child threads.
    	 * @param attributes the RequestAttributes to expose
    	 * @see #setRequestAttributes(RequestAttributes, boolean)
    	 */
    	public static void setRequestAttributes(RequestAttributes attributes) {
    		setRequestAttributes(attributes, false);
    	}

Über ②

Die Stelle, an der der Nullzeiger auftritt, ist wie folgt.

    @Autowired
    HttpServletRequest request;
    
    public void f() {
        MyClass o = (MyClass)request.getSession.getAttribute("abc");
        //Da der Wert nicht von setAttribute festgelegt wird
        o.getName();//null pointer exception
    }

Wenn es eine solche Beschreibung gibt, befindet sich die in der Anforderung festgelegte Variable irgendwo vor der Eingabe dieser Methode Es wird angenommen, dass es setAttribute ist, aber da der MVC-Test ein bestimmtes Teil angibt, ist es natürlich null, wenn es nicht gesetzt ist.

Dadurch wird eine Instanz von MockHttpSession und erstellt Festlegen und Auflösen bei mvc.perform.

Erstellen Sie zunächst eine Instanz von MockHttpSessin, indem Sie wie folgt schreiben. Methodisieren Sie so, dass Sie mehrere Sitzungsvariablen angeben können.


    public static MockHttpSession getMockHttpSession(Map<String, Object> sessions) {
            MockHttpSession mockHttpSession = new MockHttpSession();
            for (Map.Entry<String, Object> session: sessions.entrySet()) {
                mockHttpSession.setAttribute(session.getKey(), session.getValue());
            }
            return mockHttpSession;
        }

Da das Argument eine Karte ist, verwenden Sie es wie folgt. Übergeben Sie MockHttpSession zusammen mit mockMvc.perform.


    Map<String,Object> sessionMap =  new LinkedHashMap<String, Object>(){{
    	            put("id", 123);
    	            put("userName", "taro");
    	        }};
    MockHttpSession mockSession = 
            getMockHttpSession(sessionMap);
    
    
    ResultActions resultActions =
                    mockMvc.perform(MockMvcRequestBuilders.get("/data/showList")                    
                            .session(mockSession)
                            .with(user(mockAdminUser)))
                            .andExpect(MockMvcResultMatchers.status().is2xxSuccessful());

Jetzt hat die Sitzungsvariable einen Wert in der beim Testen verwendeten Methode.

Über ③

Legen Sie die als RequestScope angegebene Variable wie unten gezeigt fest Es wurde ein Nullzeiger in der Methode, die diese Variable injizierte.


    @Data//mit lombok
    class MySession {
        MyClass me;
    }
   @Bean
   @Scope(value = WebApplicationContext.SCOPE_SESSION, proxyMode = ScopedProxyMode.TARGET_CLASS)
   public MySession mySession(){
       MySession m = new MySession();
       return m;
   }
    

    @Autowired
    Mysession mySession
    
    
    public void calcService(){
        //null pointer exception
        mySession.getMe()
    }

Dies ist aus dem gleichen Grund wie ② auch natürlich, aber ich habe nach einer Methode gesucht, weil ich den Wert mit der Methode ② nicht festlegen konnte. Ich habe es durch Bezugnahme auf diesen Artikel gelöst. https://stackoverflow.com/questions/2411343/request-scoped-beans-in-spring-testing

Machen Sie die folgende Klasse Beschreiben der Registrierung von WebApplicationContext.SCOPE_SESSION.


    public class WebContextTestExecutionListener extends AbstractTestExecutionListener {
    
        @Override
        public void prepareTestInstance(TestContext testContext) {
            if (testContext.getApplicationContext() instanceof GenericApplicationContext) {
                GenericApplicationContext context = (GenericApplicationContext) testContext.getApplicationContext();
                ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
                beanFactory.registerScope(WebApplicationContext.SCOPE_REQUEST,
                        new RequestScope());
                beanFactory.registerScope(WebApplicationContext.SCOPE_SESSION,
                        new SimpleThreadScope());
            }
        }
    }

Kommentieren Sie dies der Testklasse.

    
    @ActiveProfiles("test")
    @RunWith(SpringJUnit4ClassRunner.class)
    @SpringApplicationConfiguration(classes = TestConfig.class)
    @WebIntegrationTest(randomPort = true)
    @TestExecutionListeners({WebContextTestExecutionListener.class,
            DependencyInjectionTestExecutionListener.class,
            DirtiesContextTestExecutionListener.class})
    @Transactional
    public class MvcTestSample {

Wenn Sie diese Variable zum Zeitpunkt des Testens damit einstellen In der Methode nach dem Zugriff auf mockMvc.perform Es gibt einen Wert, wenn eine Beschreibung vorhanden ist, die auf diese Variable verweist.

		@Autowired
		Mysession mySession
        
    
        @Before
        public void setUp() throws Exception {
            MyClass me = new MyClass();
            mySession.setMe(me);   
        }

Mit dem oben Gesagten konnte ich dieses Problem vorerst lösen und mit dem Schreiben des Testcodes fortfahren. Ich denke, das Testen ist absolut notwendig, aber es ist schwierig, vor dem Testen verschiedene Dinge einzurichten.

Ich habe auch auf andere Artikel zur Lösung von (2) verwiesen. Ich sollte es aus Höflichkeit verlinken, aber ich weiß nicht wo. Ich werde es verlinken, sobald ich es verstehe.

das ist alles.

Recommended Posts

Lösen Sie Nullzeiger für verschiedene Sitzungen während des MVC-Tests von Spring Boot auf.
WebMvcConfigurer-Memorandum von Spring Boot 2.0 (Spring 5)
Verschiedene Korrespondenztabellen zwischen Spring Framework und Spring Boot
Beschleunigen Sie das Testen von Validatoren, für die DI im Spring Boot erforderlich ist
Spring 5 & Spring Boot 2 Einführung für Anfänger wurde veröffentlicht
Verschiedene Switching Application.Eigenschaften für jede Umgebung, wenn Spring Boot gestartet wird
Spring Boot zum Lernen von Anmerkungen