-- Leo's gemini proxy

-- Connecting to freeshell.de:1965...

-- Connected

-- Sending request

-- Meta line: 20 text/gemini;lang=en-GB

An end-to-end test on a SpringBoot app


Preamble

Before saying anything about end-to-end testing, I have to talk about annotations. I dislike them. Let me explain. In Java you can label classes and methods with annotations that may mean something to the compiler (those ones aren't a problem), or they may just hang around at runtime so that random magic can happen. For example, if you add @Component to a class it means something like "At startup, create a single instance of this, injecting any necessary dependencies, and then inject this in turn into anything that needs it as a depenency." That always felt to me like too much magic for what is really just a label. It only works if you have a load of Spring dependencies loaded, and there's no reason why some other code couldn't use the same annotation for something completely different - identifying things that should be displayed in a GUI, for example. Different magic, same name! I'd prefer less magic and more explicitness.


Moaning aside, I have to deal with this for work, so let's see how it works for an end-to-end test.


Amble

If you have a SpringBoot app that does restful things over HTTP, you might well want to write a test that starts an instance of the app, sends it an HTTP request, and checks that the right stuff happens. This involves a heap of annotations.


The test class is something like this, assuming that there's a database involved. Everything beginning with @ is an annotation.

// package and imports elided
@SpringBootTest(webEnvironment=SpringBootTest.WebEnvironment.RANDOM_PORT)
@ActiveProfile("test")
@AutoConfigureMockMvc
class FooTest{
  @Inject MockMvc mvc;

  @Test
  @Sql(scripts={"classpath:fooTestSetup.sql"},executionPhase=Sql.ExecutionPhase.BEFORE_TEST_METHOD)
  void testFooBar(){
    // More mock setup probably goes here...
    var result = mvc.perform(get("/foo/bar"))
      .andExpect(status.ok())
      .andReturn()
      .getResponse()
      .getContentAsString();
    // Now check response body is good...
  }
}

We can assume that you already have SpringBoot as a dependency, but you need to

add the dependencies spring-boot-starter-test and h2 (an in-memory database).

add an h2 uri to your test config (something like "jdbc:h2:mem:Foo;MODE=Postgres"

create and populate tables in fooTestSetup.sql

mock any external calls the app makes to respond to the the rest call


Postamble

The good part about this is that it works, and you're doing a reasonable simulation of a real request. The bad part is all the dependencies making debugging this stuff hard because it's done automagically.


And mostly I wrote this so that I can come back and read it when I have to do this again.


#annotations

#testing


back to gemlog

-- Response ended

-- Page fetched on Sat May 4 01:52:05 2024