Search code examples
javaspringunit-testingspring-testspring-boot-test

Spring Boot Test: Inject different Resources for each unit tests


I created a @SpringBootTest-annotated class to test the HTTP responses of a REST endpoint.

I compare each HTTP JSON response with the content of a Resource.

@AutoConfigureMockMvc
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class SampleApplicationTests {

  @Autowired
  private MockMvc mockMvc;

  @Value("classpath:data/result1.json")
  private Resource result1;

  @Value("classpath:data/result2.json")
  private Resource result2;

  @Test
  public void test1() {
    mockMvc.perform(MockMvcRequestBuilders.
        get("/api/persons")).
        andExpect(MockMvcResutMatchers.status().isOk()).
        andExpect(MockMvcResutMatchers.content().json(asString(result1)));    
  }

  @Test
  public void test2() {
    mockMvc.perform(MockMvcRequestBuilders.
        get("/api/persons/1")).
        andExpect(MockMvcResutMatchers.status().isOk()).
        andExpect(MockMvcResutMatchers.content().json(asString(result2)));
  }

  ...

  private static String asString(Resource resource) {
    try {
      return IOUtils.toString(resource.getInputStream());
    } catch (IOException e) {
      throw new IllegalArgumentException(e);
    }
  }
}

I would like to know if there is a more elegant way to inject resources at the level of each test.

I know I can use ResourceLoader to load resources for each test:

@AutoConfigureMockMvc
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class SampleApplicationTests {

  @Autowired
  private ResourceLoader resourceLoader = null;

  @Test
  public void test1() {
    String result = asString(resourceLoader.getResource("classpath:data/result1.json");

    mockMvc.perform(MockMvcRequestBuilders.
        get("/api/persons")).
        andExpect(MockMvcResutMatchers.status().isOk()).
        andExpect(MockMvcResutMatchers.content().json(result));
  }
  ...
}

But I would like to know if there is an Annotation that allows to load a resource for each test. Something like the following:

@AutoConfigureMockMvc
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class SampleApplicationTests {

  @Test
  @TestResource("classpath:data/result1.json")
  public void test1(Resource result) {
    mockMvc.perform(MockMvcRequestBuilders.
        get("/api/persons")).
        andExpect(MockMvcResutMatchers.status().isOk()).
        andExpect(MockMvcResutMatchers.content().json(result));
  }
  ...
}

Does anyone have any suggestions?


Solution

  • SpringBootTest is annotated with @SpringExtension which resolves arguments for method parameters as well:

      @Test
      public void test1(@Value("classpath:data/result1.json") Resource result1) {
        // ...
      }
    
      @Test
      public void test2(@Value("classpath:data/result2.json") Resource result2) {
        // ...
      }