5

I'm looking for a way to execute some SQL scripts before my test class is executed. With Spring I can easily annotate my test class (or test method) with the @Sql annotation. I haven't found any particular way to do the same with Micronaut.

The only way I found was to manually populate the data programmatically in the test method itself, but, in my experience, there are times when you have to perform multiple inserts to test a single case.

I've came up with the following code to test a REST controller:

Code

@Validated
@Controller("/automaker")
public class AutomakerController {
    private AutomakerService automakerService;

    public AutomakerController(AutomakerService automakerService) {
        this.automakerService = automakerService;
    }

    @Get("/{id}")
    public Automaker getById(Integer id) {
        return automakerService.getById(id).orElse(null);
    }

    @Get("/")
    public List<Automaker> getAll() {
        return automakerService.getAll();
    }

    @Post("/")
    public HttpResponse<Automaker> save(@Body @Valid AutomakerSaveRequest request) {
        var automaker = automakerService.create(request);

        return HttpResponse
                .created(automaker)
                .headers(headers -> headers.location(location(automaker.getId())));

    }

    @Put("/{id}")
    @Transactional
    public HttpResponse<Automaker> update(Integer id, @Body @Valid AutomakerSaveRequest request) {
        var automaker = automakerService.getById(id).orElse(null);
        return Objects.nonNull(automaker)
                ? HttpResponse
                .ok(automakerService.update(automaker, request))
                .headers(headers -> headers.location(location(id)))
                : HttpResponse
                .notFound();
    }
}

Test

@Client("/automaker")
public interface AutomakerTestClient {
    @Get("/{id}")
    Automaker getById(Integer id);

    @Post("/")
    HttpResponse<Automaker> create(@Body AutomakerSaveRequest request);

    @Put("/{id}")
    HttpResponse<Automaker> update(Integer id, @Body AutomakerSaveRequest request);
}
@MicronautTest
public class AutomakerControllerTest {

    @Inject
    @Client("/automaker")
    AutomakerTestClient client;

    @Test
    public void testCreateAutomakerWhenBodyIsValid() {
        var request = new AutomakerSaveRequest("Honda", "Japan");
        var response = client.create(request);
        assertThat(response.code()).isEqualTo(HttpStatus.CREATED.getCode());
        var body = response.body();
        assertThat(body).isNotNull();
        assertThat(body.getId()).isNotNull();
        assertThat(body.getName()).isEqualTo("Honda");
        assertThat(body.getCountry()).isEqualTo("Japan");
    }

    @Test
    public void testUpdateAutomakerWhenBodyIsValid() {
        var responseCreated = client.create(new AutomakerSaveRequest("Chvrolet", "Canada"));
        assertThat(responseCreated.code()).isEqualTo(HttpStatus.CREATED.getCode());
        var itemCreated = responseCreated.body();
        assertThat(itemCreated).isNotNull();
        var responseUpdated = client.update(itemCreated.getId(), new AutomakerSaveRequest("Chevrolet", "United States"));
        assertThat(responseUpdated.code()).isEqualTo(HttpStatus.OK.getCode());
        var itemUpdated = responseUpdated.body();
        assertThat(itemUpdated).isNotNull();
        assertThat(itemUpdated.getName()).isEqualTo("Chevrolet");
        assertThat(itemUpdated.getCountry()).isEqualTo("United States");
    }
}

I could use a method annotated with @Before to populate all the data I need but it would really be nice to be able to use *.sql scripts the way it is possible with Spring. Is there a way to provide such *.sql scripts before the tests are executed ?

1 Answers1

2

TL;DR — Use Flyway.

With Flyway, you can set up and maintain a given database schema (extremely) easily. To your case, any migration script you put under ../test/resources/db/migration/ (or any other default location you set) will be only visible to your tests, and can be executed/run automatically (if configured) any time you run your tests.

Another solution would be to use an in-memory database (but I would stay away from that for real applications). For instance, H2 have a way to specify an "initialization" script and another for data seeding (and such).

x80486
  • 6,627
  • 5
  • 52
  • 111
  • You read my thoughts. I was about to try Flyway for this, but, since this is just an experimentation project, I think I will try this H2 "initialization" script (I didn't knew this feature). I will try to post an example later. – Leonardo Barbieri Oct 21 '19 at 13:19