Java >> Java tutorial >  >> Tag >> Spring

Test af Spring Data + Spring Boot-applikationer med Arquillian (del 2)

I forrige indlæg skrev jeg om, hvordan man tester Forårsdata applikation ved hjælp af Docker med Arquillian Cube . Testen så sådan ud:

@RunWith(SpringRunner.class)
@SpringBootTest(classes = PingPongController.class, webEnvironment = RANDOM_PORT)
@ContextConfiguration(initializers = PingPongSpringBootTest.Initializer.class)
public class PingPongSpringBootTest {

    @ClassRule
    public static ContainerDslRule redis = new ContainerDslRule("redis:3.2.6")
                                                .withPortBinding(6379);

    @Autowired
    TestRestTemplate restTemplate;

    @Test
    public void should_get_pongs() {

        // given

        restTemplate.postForObject("/ping", "pong", String.class);
        restTemplate.postForObject("/ping", "pung", String.class);

        // when

        final List<String> pings = restTemplate.getForObject("/ping", List.class);

        // then

        assertThat(pings)
            .hasSize(2)
            .containsExactlyInAnyOrder("pong", "pung");
    }

    public static class Initializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
        @Override
        public void initialize(ConfigurableApplicationContext configurableApplicationContext) {
            EnvironmentTestUtils.addEnvironment("testcontainers", configurableApplicationContext.getEnvironment(),
                "spring.redis.host=" + redis.getIpAddress(),
                "spring.redis.port=" + redis.getBindPort(6379)
            );
        }
    }

}

Denne test starter lige Redis container, og udfyld derefter data ved hjælp af restTemplate og indlæg metode, og udfør derefter logikken under test (test af GET HTTP metode) og til sidst stoppe Redis container.
Det er godt, det virker, men der er flere problemer der:<

  • Den første er, at vi bruger REST API at forberede datasæt af testen. Problemet her er, at testen muligvis mislykkes, ikke på grund af en fejl på kode under test, men på grund af forberedelsen af ​​testen (indsættelse af data).
  • Den anden er, at hvis POST endepunkt ændrer format/placering, så skal du huske at ændre alle steder i testene, hvor det bruges.
  • Den sidste er, at hver test skal forlade miljøet som fundet før udførelse, så testen er isoleret fra alle udførelser. Problemet er, at for at gøre det i denne tilgang skal du slette de tidligere elementer indsat af POST . Det betyder at tilføje SLET HTTP metode, som måske ikke altid er implementeret i slutpunktet, eller den kan være begrænset til nogle konkrete brugere, så de er nødt til at håndtere særlige godkendelsesting.

For at undgå dette problem Arquillian Persistence Extension (alias APE ) var lavet. Disse udvidelser integreres med DBUnit og Flyway til SQL databaser, NoSQLUnit for Ingen SQL databaser og Postmand-samlinger til REST tjenester, så du kan udfylde din backend, før du tester den rigtige testbrug, og rense persistenslageret efter testen er udført.

Også befolkningsdata er gemt inde i en fil, så det betyder, at de kan genbruges i alle test og nemt ændres i tilfælde af enhver skemaopdatering.
Lad os se eksempel på del 1 af indlægget, men opdatering til brug af APE .

@RunWith(SpringRunner.class)
@SpringBootTest(classes = PingPongController.class, webEnvironment = RANDOM_PORT)
@ContextConfiguration(initializers = PingPongSpringBootTest.Initializer.class)
public class PingPongSpringBootTest {

    @ClassRule
    public static ContainerDslRule redis = new ContainerDslRule("redis:3.2.6")
                                                .withPortBinding(6379);

    @Rule
    public ArquillianPersistenceRule arquillianPersistenceRule = new ArquillianPersistenceRule();

    @Autowired
    TestRestTemplate restTemplate;

    @Redis
    @ArquillianResource
    NoSqlPopulator populator;

    @Test
    public void should_get_pongs() {

        // given

        populator.forServer(redis.getIpAddress(), redis.getBindPort(6379))
                 .usingDataSet("pings.json")
                 .execute();

        // when

        final List<String> pings = restTemplate.getForObject("/ping", List.class);

        // then

        assertThat(pings)
            .hasSize(2)
            .containsExactlyInAnyOrder("pong", "pung");
    }

    @After
    public void clean_database() {
        populator.forServer(redis.getIpAddress(), redis.getBindPort(6379))
            .clean();
    }

    public static class Initializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
        @Override
        public void initialize(ConfigurableApplicationContext configurableApplicationContext) {
            EnvironmentTestUtils.addEnvironment("testcontainers", configurableApplicationContext.getEnvironment(),
                "spring.redis.host=" + redis.getIpAddress(),
                "spring.redis.port=" + redis.getBindPort(6379)
            );
        }
    }

}

Og filen (pings.json ) bruges til at udfylde Redis instans med data ser sådan ud:

{
  "data" : [
    {
      "list" : [
        {
          "key" : "ping",
          "values" : [
            {
              "value" : "pong"
            },
            {
              "value" : "pung"
            }
          ]
        }
      ]
    }
  ]
}
Bemærk, at du i denne test har erstattet POST kalder på noget, der direkte sættes ind i lageret. På denne måde undgår du enhver fejl, der måtte opstå i indsættelseslogikken (som ikke er den del, der testes). Til sidst efter hver testmetode, Redis instans er renset, så andre test finder Redis rent og i kendt tilstand.
Projektet kan findes på https://github.com/arquillian-testing-microservices/pingpongbootredis
Java tag