Volodya Lombrozo
Volodya Lombrozo

Reputation: 3454

Spring Boot integration test. How to test the 'DELETE' method?

I'm using Spring Boot 2.5.6 and JUnit 4.13.2. My task is to test the DELETE method

My REST controller:

@RestController
public class DomainEndpoint {

    private final SomeService service;

    @DeleteMapping("/domain/{id}")
    public void delete(@PathVariable long id) {
        service.delete(id);
    }
}

My test:

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@RunWith(SpringRunner.class)
public class DomainEndpointTest {

    @Autowired
    TestRestTemplate template;

    @MockBean
    SomeService service;

    @Test
    public void delete() {
        String url = "/domain/123";
        ResponseEntity<?> resp = template.exchange(url, HttpMethod.DELETE, new HttpEntity<>(""), String.class);
        assertEquals(HttpStatus.NO_CONTENT, resp.getStatusCode());
    }
}

As you can see, the only solution for testing the 'DELETE' method, which I found, is:

ResponseEntity<?> resp = template.exchange(url, HttpMethod.DELETE, new HttpEntity<>(""), String.class);

But params for body new HttpEntity<>("") and for return type String.class seem strange to me. Why should I use them? Can I do the same more straightway without passing unnecessary parameters?
On the other hand, TestRestTemplate template has a set of short and readable methods delete(). The problem with them - they return void and I can't check the response status code in this case.

The main question is how to test DELETE methods correctly?

Upvotes: 0

Views: 4153

Answers (5)

spyro
spyro

Reputation: 515

If you are using Kotin, feel free to use this extension methods :)

/**
 * Extension for using PUT (not provided by default)
 */
inline fun <RQ : Any, reified RP : Any> TestRestTemplate.putForEntity(url: String, payload: RQ): ResponseEntity<RP> =
    this.exchange(url, PUT, HttpEntity(payload))

/**
 * Extension for [TestRestTemplate] DELETE (not provided by default, whyever)
 */
inline fun <reified RQ : Any> TestRestTemplate.deleteForEntity(url: String): ResponseEntity<RQ> =
    this.exchange(url, DELETE)

/**
 * Extension for [TestRestTemplate] DELETE with payload (not provided by default, whyever)
 */
inline fun <reified RQ : Any, reified RP : Any> TestRestTemplate.deleteForEntity(
    url: String,
    payload: RQ
): ResponseEntity<RP> = this.exchange(url, DELETE, HttpEntity(payload))

Upvotes: 0

user3075118
user3075118

Reputation: 131

In my opinion RestTemplate.delete method is the one to use, return type is void but status other than 2XX will throw an exception.

Upvotes: 0

Shailendra
Shailendra

Reputation: 9102

Others have given different options but if you want to use the the delete method - it internally handles the http error by throwing runtime error as you can see here. You can check for HttpClientErrorException or HttpServerErrorException by using assertDoesNotThrow from JUnit5

Upvotes: 0

Matt Fowler
Matt Fowler

Reputation: 2733

Instead of passing in new HttpEntity<>("") HttpEntity has a special class variable you can use called HttpEntity.EMPTY for these situations. You can also use a return type of void.

ResponseEntity<Void> resp = template.exchange(url, HttpMethod.DELETE, HttpEntity.EMPTY, Void.class);

Upvotes: 4

slauth
slauth

Reputation: 3178

Two things you could improve:

  1. Don't provide a request entity – it is marked as @Nullable
  2. Use Void.class as return type to express that you don't expect any response body
ResponseEntity<Void> resp = restTemplate.exchange(url, HttpMethod.DELETE, null, Void.class);

Upvotes: 1

Related Questions