Kontekst aplikacji w Springu
Kontekst aplikacji w Springu
W momencie startu aplikacji Spring tworzy jej kontekst gdzie rejestrowane są obiekty przez niego zarządzane. W aplikacji zazwyczaj tworzony jest tylko jeden kontekst natomiast nie jest to regułą. Kontekstów związanych z aplikacją może być wiele, ale jest to bardzo rzadko stosowana praktyka. Klasą która reprezentuje kontekst aplikacji jest ApplicationContext:
@SpringBootApplication public class SonarDemoApplication { public static void main(String[] args) { new SonarDemoApplication().run(args); } private void run(String[] args) { ApplicationContext context = SpringApplication.run(SonarDemoApplication.class, args); System.out.println(context.getBean("restCalculatorController")); } }
jeśli typ aplikacji to aplikacja webowa to domyślnym kontekstem Springa jest WebApplicationContext który pobiera ServletContext odpowiadający za obsługę żądań protokołu HTTP:
public interface WebApplicationContext extends ApplicationContext { ServletContext getServletContext(); }
adnotację @SpringBootApplication użytą w powyższym przykładzie można zapisać w postaci:
@SpringBootApplication = @Configuration + @ComponentScan + @EnableAutoConfiguration
Jeśli chcemy np. skonfigurować ViewResolver dla plików JSP to musimy dodać nowe zachowanie do obsługi żądań HTTP w aplikacji. W tym celu przyda się adnotacja @EnableWebMvc:
@Configuration @EnableWebMvc @ComponentScan public class MvcConfiguration extends WebMvcConfigurerAdapter { @Override public void configureViewResolvers(ViewResolverRegistry registry) { InternalResourceViewResolver resolver = new InternalResourceViewResolver(); resolver.setPrefix("/WEB-INF/view/"); resolver.setSuffix(".jsp"); resolver.setViewClass(JstlView.class); registry.viewResolver(resolver); } }
Jeśli w pliku pom.xml dodana zostanie zależność:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency>
to adnotacja @EnableWebMvc dodana jest automatycznie.
Adnotacja @SpringBootTest to adnotacja którą używamy kiedy podczas testów chcemy uruchomić pełny kontekst Springa a tym załadować z kolei wszystkie obiekty przez niego zarządzane. Nie jest natomiast uruchamiany serwer HTTP! Uruchomienie kontekstu Springa wraz z pełnym serwerem HTTP możliwe jest jeśli użyty zostanie parametr:
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
Adnotacja @WebMvcTest to adnotacja która pozwala na testy integracyjne kontrolerów (klasy oznaczone adnotacją @Controller czy @RestController). Użycie tej adnotacji spowoduje, że klasy oznaczone np. adnotacją @Component nie zostaną dodane do kontekstu. Testy takie są mniej kosztowne ponieważ trwają mniej czasu. Ponadto możliwe jest wyspecyfikowanie który kontroler zostanie użyty do testów.
Niżej zamieszczony przykład pokazuje proste użycie adnotacji @SpringBootTest – do pliku pom.xml dodajemy zależność:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency>
Klasa modelu:
@Getter @Setter public class Person { String username; String surname; int salary; }
RestController:
@RestController public class PersonController { @RequestMapping(value = "/person", method = RequestMethod.GET) public Person getPerson() { Person person = new Person(); person.setUsername("James"); person.setSurname("Spring"); person.setSalary(1000); return person; } }
Po wejściu na:
http://localhost:8080/person
otrzymujemy wynik:
Klasa z adnotacjami po której klasy testowe będą dziedziczyć:
@ContextConfiguration @RunWith(SpringRunner.class) @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) class SpringBootUnitTestApplicationTests { @Test void contextLoads() { } }
testy integracyjne RestControllera:
public class TestWebApp extends SpringBootUnitTestApplicationTests { @LocalServerPort private int port; @Autowired private TestRestTemplate template; private URL base; @Before public void setUp() throws Exception { this.base = new URL("http://localhost:" + port + "/"); } @Test public void getPersonContent() throws Exception { System.out.println(this.base); ResponseEntity<String> response = template.getForEntity(base.toString() + "person", String.class); HashMap<String,Object> result = new ObjectMapper().readValue(response.getBody(), HashMap.class); Assert.assertEquals(result.get("username"), "James"); Assert.assertEquals(result.get("surname"), "Spring"); Assert.assertEquals(result.get("salary"), 1000); } }
Leave a comment