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

Zobacz kod na GitHubie i zapisz się na bezpłatny newsletter!

.

Leave a comment

Your email address will not be published.


*