spring-boot
Test in Spring Boot
Ricerca…
Come testare una semplice applicazione di avvio a molla
Abbiamo un'applicazione di avvio Spring di esempio che memorizza i dati dell'utente in MongoDB e stiamo utilizzando i servizi di Rest per recuperare i dati
Prima c'è una classe di dominio, ad esempio POJO
@Document
public class User{
@Id
private String id;
private String name;
}
Un repository corrispondente basato su Spring Data MongoDB
public interface UserRepository extends MongoRepository<User, String> {
}
Quindi il nostro controller utente
@RestController
class UserController {
@Autowired
private UserRepository repository;
@RequestMapping("/users")
List<User> users() {
return repository.findAll();
}
@RequestMapping(value = "/Users/{id}", method = RequestMethod.DELETE)
@ResponseStatus(HttpStatus.NO_CONTENT)
void delete(@PathVariable("id") String id) {
repository.delete(id);
}
// more controller methods
}
E infine la nostra applicazione Spring Boot
@SpringBootApplication
public class Application {
public static void main(String args[]){
SpringApplication.run(Application.class, args);
}
}
Se, diciamo che John Cena, The Rock e TripleHHH erano gli unici tre utenti nel database, una richiesta a / utenti avrebbe dato la seguente risposta:
$ curl localhost:8080/users
[{"name":"John Cena","id":"1"},{"name":"The Rock","id":"2"},{"name":"TripleHHH","id":"3"}]
Ora per testare il codice verificheremo che l'applicazione funzioni
@RunWith(SpringJUnit4ClassRunner.class) // 1
@SpringApplicationConfiguration(classes = Application.class) // 2
@WebAppConfiguration // 3
@IntegrationTest("server.port:0") // 4
public class UserControllerTest {
@Autowired // 5
UserRepository repository;
User cena;
User rock;
User tripleHHH;
@Value("${local.server.port}") // 6
int port;
@Before
public void setUp() {
// 7
cena = new User("John Cena");
rock = new User("The Rock");
tripleHHH = new User("TripleHH");
// 8
repository.deleteAll();
repository.save(Arrays.asList(cena, rock, tripleHHH));
// 9
RestAssured.port = port;
}
// 10
@Test
public void testFetchCena() {
String cenaId = cena.getId();
when().
get("/Users/{id}", cenaId).
then().
statusCode(HttpStatus.SC_OK).
body("name", Matchers.is("John Cena")).
body("id", Matchers.is(cenaId));
}
@Test
public void testFetchAll() {
when().
get("/users").
then().
statusCode(HttpStatus.SC_OK).
body("name", Matchers.hasItems("John Cena", "The Rock", "TripleHHH"));
}
@Test
public void testDeletetripleHHH() {
String tripleHHHId = tripleHHH.getId();
when()
.delete("/Users/{id}", tripleHHHId).
then().
statusCode(HttpStatus.SC_NO_CONTENT);
}
}
Spiegazione
- Come qualsiasi altro test basato su Spring, abbiamo bisogno di
SpringJUnit4ClassRunner
perSpringJUnit4ClassRunner
un contesto applicativo. - L'annotazione
@SpringApplicationConfiguration
è simile all'annotazione@ContextConfiguration
in quanto viene utilizzata per specificare i contesti di applicazione da utilizzare nel test. Inoltre, attiverà la logica per la lettura delle configurazioni, delle proprietà e così via di Spring Boot. -
@WebAppConfiguration
deve essere presente per dire a Spring che unWebApplicationContext
deve essere caricato per il test. Fornisce anche un attributo per specificare il percorso alla radice dell'applicazione web. -
@IntegrationTest
viene utilizzato per indicare a Spring Boot che il server Web incorporato deve essere avviato. Fornendo coppie di nomi / valori separati da due punti o da due punti, qualsiasi variabile d'ambiente può essere sovrascritta. In questo esempio,"server.port:0"
sostituirà l'impostazione della porta predefinita del server. Normalmente, il server inizia a utilizzare il numero di porta specificato, ma il valore 0 ha un significato speciale. Se specificato come 0, indica a Spring Boot di eseguire la scansione delle porte sull'ambiente host e avviare il server su una porta casuale disponibile. Ciò è utile se disponiamo di servizi diversi che occupano porte diverse sui computer di sviluppo e sul build server che potrebbero potenzialmente entrare in collisione con la porta dell'applicazione, nel qual caso l'applicazione non verrà avviata. In secondo luogo, se creiamo più test di integrazione con diversi contesti applicativi, possono anche scontrarsi se i test vengono eseguiti contemporaneamente. - Abbiamo accesso al contesto dell'applicazione e possiamo utilizzare l'autowiring per iniettare qualsiasi bean Spring.
- Il valore
@Value("${local.server.port}”)
verrà risolto sul numero di porta effettivo che viene utilizzato. - Creiamo alcune entità che possiamo usare per la convalida.
- Il database MongoDB viene cancellato e reinizializzato per ciascun test in modo da essere sempre convalidati rispetto a uno stato noto. Poiché l'ordine dei test non è definito, è probabile che il test testFetchAll () non riesca se viene eseguito dopo il test testDeletetripleHHH ().
- Forniamo a Rest Assured l'uso della porta corretta. È un progetto open source che fornisce un DSL Java per testare i servizi restful
- I test sono implementati usando Rest Assured. possiamo implementare i test utilizzando TestRestTemplate o qualsiasi altro client http, ma io utilizzo Rest Assured perché possiamo scrivere documentazione concisa usando RestDocs
Caricare file yaml [o proprietà] diversi o sovrascrivere alcune proprietà
Quando usiamo @SpringApplicationConfiguration
userà la configurazione da application.yml
[proprietà] che in determinate situazioni non è appropriata. Quindi per sovrascrivere le proprietà possiamo usare @TestPropertySource
annotazione @TestPropertySource
.
@TestPropertySource(
properties = {
"spring.jpa.hibernate.ddl-auto=create-drop",
"liquibase.enabled=false"
}
)
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(Application.class)
public class ApplicationTest{
// ...
}
Possiamo usare l'attributo properties di @TestPropertySource
per sovrascrivere le proprietà specifiche che vogliamo. Nell'esempio precedente stiamo spring.jpa.hibernate.ddl-auto
override della proprietà spring.jpa.hibernate.ddl-auto
su create-drop
. E liquibase.enabled
a false
.
Caricamento di file yml diversi
Se si desidera caricare completamente un file yml diverso per il test, è possibile utilizzare l'attributo locations su @TestPropertySource
.
@TestPropertySource(locations="classpath:test.yml")
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(Application.class)
public class ApplicationTest{
// ...
}
In alternativa opzioni
Opzione 1:
Puoi anche caricare diversi file yml inserendo un file yml nella directory test > resource
Opzione 2:
Utilizzo dell'annotazione @ActiveProfiles
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = Application.class)
@ActiveProfiles("somename")
public class MyIntTest{
}
Puoi vedere che stiamo usando @ActiveProfiles
annotazione @ActiveProfiles
e stiamo passando il somename come valore.
Crea un file chiamato application-somename.yml
e il test caricherà questo file.