Zoeken…


Hoe een eenvoudige Spring Boot-toepassing te testen

We hebben een voorbeeld Spring boot-applicatie die gebruikersgegevens opslaat in MongoDB en we gebruiken Rest-services om gegevens op te halen

Eerst is er een domeinklasse ie POJO

@Document
public class User{
    @Id
    private String id;

    private String name;

}

Een bijbehorende repository op basis van Spring Data MongoDB

public interface UserRepository extends MongoRepository<User, String> {
}

Dan onze gebruikerscontroller

@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
}

En tot slot onze Spring Boot Application

@SpringBootApplication
public class Application {
    public static void main(String args[]){
     SpringApplication.run(Application.class, args);
    }
}

Als, laten we zeggen dat John Cena, The Rock en TripleHHH de enige drie gebruikers in de database waren, zou een verzoek aan / gebruikers het volgende antwoord geven:

$ curl localhost:8080/users
[{"name":"John Cena","id":"1"},{"name":"The Rock","id":"2"},{"name":"TripleHHH","id":"3"}]

Om de code te testen, zullen we controleren of de toepassing werkt

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

Uitleg

  1. Net als elke andere op Spring gebaseerde test hebben we de SpringJUnit4ClassRunner zodat een toepassingscontext wordt gemaakt.
  2. De annotatie @SpringApplicationConfiguration is vergelijkbaar met de annotatie @ContextConfiguration omdat deze wordt gebruikt om aan te geven welke toepassingscontext (en) in de test moeten worden gebruikt. Bovendien zal het logica activeren voor het lezen van Spring Boot-specifieke configuraties, eigenschappen, enzovoort.
  3. @WebAppConfiguration moet aanwezig zijn om Spring te laten weten dat een WebApplicationContext moet worden geladen voor de test. Het biedt ook een kenmerk voor het opgeven van het pad naar de hoofdmap van de webtoepassing.
  4. @IntegrationTest wordt gebruikt om Spring Boot te vertellen dat de geïntegreerde webserver moet worden gestart. Door dubbele of gelijk-gescheiden naam-waardeparen te verstrekken, kan elke omgevingsvariabele worden overschreven. In dit voorbeeld overschrijft de "server.port:0" de standaardpoortinstelling van de server. Normaal gesproken begint de server het opgegeven poortnummer te gebruiken, maar de waarde 0 heeft een speciale betekenis. Wanneer gespecificeerd als 0, vertelt Spring Boot om de poorten in de hostomgeving te scannen en de server op een willekeurige, beschikbare poort te starten. Dat is handig als we verschillende services hebben die verschillende poorten op de ontwikkelmachines en de build-server bezetten die mogelijk in botsing kunnen komen met de applicatiepoort, in welk geval de applicatie niet start. Ten tweede, als we meerdere integratietests maken met verschillende toepassingscontexten, kunnen ze ook botsen als de tests tegelijkertijd worden uitgevoerd.
  5. We hebben toegang tot de toepassingscontext en kunnen autowiring gebruiken om elke springboon te injecteren.
  6. De @Value("${local.server.port}”) wordt omgezet in het daadwerkelijke poortnummer dat wordt gebruikt.
  7. We maken enkele entiteiten die we kunnen gebruiken voor validatie.
  8. De MongoDB-database wordt gewist en opnieuw geïnitialiseerd voor elke test, zodat we altijd valideren tegen een bekende status. Aangezien de volgorde van de tests niet is gedefinieerd, is de kans groot dat de test testFetchAll () mislukt als deze wordt uitgevoerd na de test testDeletetripleHHH ().
  9. We geven Rest Assured de juiste poort te gebruiken. Het is een open source-project dat een Java DSL biedt voor het testen van rustgevende services
  10. Tests worden uitgevoerd met Rest Assured. we kunnen de tests uitvoeren met behulp van de TestRestTemplate of een andere http-client, maar ik gebruik Rest Assured omdat we beknopte documentatie kunnen schrijven met RestDocs

Een ander yaml [of eigenschappen] bestand laden of sommige eigenschappen overschrijven

Wanneer we @SpringApplicationConfiguration gebruiken, gebruikt het configuratie van application.yml [eigenschappen] die in bepaalde situaties niet geschikt is. Om de eigenschappen te negeren, kunnen we de annotatie @TestPropertySource gebruiken.

@TestPropertySource(
        properties = {
                "spring.jpa.hibernate.ddl-auto=create-drop",
                "liquibase.enabled=false"
        }
)
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(Application.class)
public class ApplicationTest{

    // ...

}

We kunnen het eigenschappenkenmerk van @TestPropertySource gebruiken om de specifieke eigenschappen te overschrijven die we willen. In het bovenstaande voorbeeld overschrijven we eigenschap spring.jpa.hibernate.ddl-auto om create-drop te create-drop . En liquibase.enabled naar false .

Verschillende YML-bestanden laden

Als u een ander yml- bestand voor de test wilt laden, kunt u het locatiekenmerk gebruiken op @TestPropertySource .

@TestPropertySource(locations="classpath:test.yml")
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(Application.class)
public class ApplicationTest{

    // ...

}

Alternatieve opties

Optie 1:

U kunt ook verschillende yml- bestanden laden door een yml- bestand in test > resource map test > resource

Optie 2:

Annotatie met @ActiveProfiles gebruiken

@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = Application.class)
@ActiveProfiles("somename")
public class MyIntTest{
}

U kunt zien dat we met behulp van @ActiveProfiles annotatie en we zijn het passeren van de somename als de waarde.

Maak een bestand met de naam application-somename.yml en de test laadt dit bestand.



Modified text is an extract of the original Stack Overflow Documentation
Licentie onder CC BY-SA 3.0
Niet aangesloten bij Stack Overflow